输入处理

鼠标/触摸输入

FairyGUI使用内置的机制进行鼠标和触摸事件的处理,不使用射线。如果确实要使用射线,可以将UIPanel的“HitTest Mode”设置为“Raycast”。无论哪种点击检测模式,下面的事件处理机制都一样。

如果要区分点击UI还是点击场景里的对象,可以使用下面的方法:

  1. if(Stage.isTouchOnUI) //点在了UI上
    {
    }
    else //没有点在UI上
    {
    }

这种检测不仅适用于点击,也适用于悬停。例如,如果鼠标悬停在UI上,这个判断也是真。如果你觉得屏幕上都没有UI了这个还是返回真,那就真的是有UI,特别是全屏界面,没设置穿透时,它的空白区域也是接受输入的。你可以通过打印GRoot.inst.touchTarget检查。

和鼠标/触摸相关的事件有:

  • onTouchBegin 鼠标按键按下(左、中、右键),或者手指按下。鼠标按钮可以从context.inputEvent.button获得,0-左键,1-中键,2-右键。
  • onTouchMove 鼠标指针移动或者手指在屏幕上移动。这个事件只有两种情况会触发:
    • 在onTouchBegin里调用了context.CaptureTouch(),那么后续的移动事件都会在这个对象上触发(无论手指或指针位置是不是在该对象上方)。
    • 舞台的onTouchMove始终会触发,即Stage.inst.onTouchMove,它不需要使用CaptureTouch捕获。在PC平台上鼠标只要移动,就可以触发;在手机平台上,只有手指按下后移动才会触发。
  • onTouchEnd 鼠标按键释放或者手指从屏幕上离开。如果鼠标或者触摸位置已经不在组件范围内了,那么组件的TouchEnd事件是不会触发的,如果确实需要,可以在onTouchBegin里调用context.CaptureTouch()请求捕获。
  • onClick 鼠标或者手指点击。可以从context.inputEvent.isDoubleClick判断是否双击。如果你在找长按事件,那么请使用LongPressGesture(长按手势)。**在手指按下后,如果调用Stage.inst.CancelClick,手指抬起时就不会触发Click事件。**
  • onRightClick 鼠标右键点击。
  • onRollOver 鼠标或者手指移入一个元件时触发。
  • onRollOut 鼠标或者手指移出一个元件时触发。在任何事件(即不只是鼠标/触摸相关的事件)回调中都可以获得当前鼠标或手指位置,以及点击的对象,例如:
  1. void AnyEventHandler(EventContext context)
    {
    //点击位置,注意是屏幕坐标,要转换本地坐标要使用GlobalToLocal
    Debug.Log(context.inputEvent.x + ", " + context.inputEvent.y);
    //获取点击的对象(在鼠标/触摸事件中)
    Debug.Log((GObject)context.sender);
    //如果事件是冒泡的,可以获得最底层的对象。但要注意,这里的对象类型是DisplayObject,不是GObject。
    Debug.Log((DisplayObject)context.initiator);
    }

如果不在事件中,需要获得当前鼠标或者手指的位置,可以用:

  1. //这是鼠标的位置,或者最后一个手指的位置
    Vector2 pos1 = Stage.inst.touchPosition;
    //获取指定手指的位置,参数是手指id
    Vector2 pos2 = Stage.inst.GetTouchPosition(1);

在任何时候,如果需要获得当前点击的对象,或者鼠标下的对象,都可以通过以下的方式获得:

  1. GObject obj = GRoot.inst.touchTarget;
    //判断是不是在某个组件内
    Debug.Log(testComponent==obj || testComponent.IsAncestorOf(obj));

多点触摸

FairyGUI支持多点触摸的处理。每个手指都会按照TouchBegin->TouchMove->TouchEnd流程派发事件,可以使用EventContext.inputEvent.touchId区分不同的手指。一般来说,普通的点击事件无需关心手指id,只有需要用到整个触摸流程的才需要处理。

  1. //这是当前按下的手指的数量
    int touchCount = Stage.inst.touchCount;
    //获得当前所有按下的手指id
    int[] touchIDs = Stage.inst.GetAllTouch(null);

如果你不想使用多点触摸功能,可以使用Unity的API:Input.multiTouchEnabled = false关闭。

VR输入处理

VR里输入一般使用凝视输入,或者手柄输入,针对这些新的输入方式,FairyGUI提供了封装支持,也就是说,在VR应用里,你仍然可以像处理鼠标或者触摸输入一样处理VR的输入,无任何区别,也就是说UI逻辑不需要做任何修改。

首先,需要把这些外部输入传入FairyGUI。在Stage类里提供了这些API:

  1. public void SetCustomInput(ref RaycastHit hit, bool buttonDown);
    public void SetCustomInput(ref RaycastHit hit, bool buttonDown, bool buttonUp);
  • hit 没有手柄的,这里传入眼睛的射线(其实就是摄像机的射线)击中的目标;有手柄的,传入手柄射线击中的目标。

  • buttonDown 是否有按键按下。对于没有buttonUp参数的API,系统会在下一帧自动模拟一个buttonUp。

  • buttonUp 是否有按键松开。按下、松开整个过程构成一次点击。如果只有按下没有松开,则不会有点击触发,必须注意这一点。

SetCustomInput可以放在Update里调用,而且必须每帧调用。如果使用了SetCustomInput,则FairyGUI不再处理鼠标或者触摸输入。

使用示例:

  1. SteamVR_TrackedObject controller;
    SteamVR_Controller.Device controllerDevice;
    void Start()
    {
    controller = ...
    controllerDevice = ...
    }
    void Update()
    {
    Vector3 pos = controller.transform.position;
    Vector3 dir = controller.transform.forward;
    bool trigger_down = controllerDevice.GetPress(Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger);
    RaycastHit rh;
    if (Physics.Raycast(pos, dir, out rh))
    {
    Stage.inst.SetCustomInput(rh, trigger_down);
    }
    }

键盘输入

侦听键盘输入的方法是:

  1. Stage.inst.onKeyDown.Add(OnKeyDown);
    void OnKeyDown(EventContext context)
    {
    Debug.Log(context.inputEvent.keyCode);
    }

在手机上是通过原生的键盘输入。键盘弹出时,派发GTextInput.onFocusIn事件,键盘收回时,派发GTextInput.onFocusOut事件。

Unity在键盘输入时自带了一个额外的输入框,如果你不需要这个输入框,希望像微信那样弹出自己的输入框,你需要自行编写原生代码,FairyGUI这边提供的支持有:

  1. //定义自己的键盘
    KeyBoard yourKeyboard;
    Stage.inst.keyboard = yourKeyboard;

复制粘贴问题

当使用DLL形式的插件时,因为DLL默认是为移动平台编译的,所以不支持复制粘贴(如果要支持,需要自己写原生代码支持)。如果是在PC平台上使用时,需要将CopyPastePatch.cs放到工程里,并在游戏启动时调用CopyPastePatch.Apply(),就可以在PC平台激活复制粘贴功能。如果你是使用源码形式的插件,不需要进行这个处理。

手势

FairyGUI提供了手势的支持。使用手势的方式是:

  1. LongPressGesture gesture = new LongPressGesture(targetObject);
    gesture.onAction.Add(OnGestureAction);

targetObject是接收手势的元件,注意一定要是可触摸的。图片是不可触摸的,一般建议用组件,或者装载器。如果你需要全屏幕监测手势,那么可以直接用GRoot.inst作为targetObject(需1.9.0 SDK或更高版本支持)

常用的手势有:

LongPressGesture 长按手势。可以设定长按触发的时间,还可以控制长按触发后继续触发通知的时间间隔。

SwipeGesture 手指划动手势。

PinchGesture两指缩放手势。

RotationGesture 两指旋转手势。

手势的使用方法可以参考Gesture这个Demo。手势与FairyGUI SDK是非耦合的,也就是说,如果你觉得手势不符合你的要求,你可以复制一个出来自己改自己用。