Unity3d---对UI事件接口的一些测试和机制(坑)的总结
开文来记录一下自己摸索到的UI事件接口的一些运作机制(坑),就不赘述具体怎么使用这些事件接口了(不做教学...),本文主要是记自己发现的一些坑点
主要针对于在复杂的UI嵌套关系下,鼠标指针和拖拽操作的事件接口的调用关系 ,一些容易出错的地方进行记录
欢迎各路神仙留言指正,若能不吝赐教,鄙人先谢为敬
版本:Unity 2019.3.0
emmmmmm
怎么好像之前Unity2018的跨父对象层级的Drop方法还无法正常调用来着,做背包系统的时候真的坑死了,现在2019这个坑是被官方填了?
1.还是提一下什么是UI事件接口
在UGUI中通过 using UnityEngine.EventSystems;
可以让继承自Mono的脚本实现一些丰富的事件接口, 这些被实现接口方法会在进行UI交互的一些特定的行为出现时被调用
主要包括Point鼠标指针操作,Drag/Drop拖拽操作,Select点选操作,Input鼠标键盘输入类
UI事件接口主要用于UI上的一些物体(Image,Button一类),也可以应用到场景中一些3D物体
UI事件接口能够在 PC鼠标 和 触屏 两种操作模式下被正确的使用
在使用中UI事件接口与EventTrigger实现的交互事件区别在于, 当某个UI物体需要被设计为一个对象 ,在 针对它的特定的交互行为出现 时 调用该对象自身的一些方法 ,实现一些交互功能时, 应使用UI事件接口 的实现方法,将脚本挂在该物体上。而当 某个UI物体不需要被设计为一个对象 ,在 针对它的特定的交互行为出现时,需要去调用别的物体上某个组件的方法 来实现一些交互功能时, 应使用EventTrigger的实现方法,添加EventTrigger,添加交互行为并绑定别的物体上特定组件的特定方法
UI事件接口和EventTrigger能被正确调用的预备条件一致,即:
针对UI物体时,场景中应创建EventSystem,UI物体的RectTransform需要有一定的宽高
针对3D物体时,场景中应创建EventSystem,摄像机应添加Physics Raycaster组件,3D物体需要有Collider组件
2.准备一下测试
场景物体摆放即父子关系
分别给两个Panel添加一个名为 Test_IEP的脚本
给所有 Button 和 Image 都添加一个名为 Test_IEC的脚本
3.IPointer 鼠标点击事件接口测试
---3.1 父子均实现 IPointerDownHandler, IPointerUpHandler (出现覆盖问题)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestIEP : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
public void OnPointerUp(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnPointerUp");
public void OnPointerDown(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnPointerDown");
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestIEC : MonoBehaviour,IPointerDownHandler,IPointerUpHandler
public void OnPointerUp(PointerEventData eventData)
Debug.Log("C:" + gameObject.name + " OnPointerUp");
public void OnPointerDown(PointerEventData eventData)
Debug.Log("C:" + gameObject.name + " OnPointerDown");
------3.1.1 分别点击Panel没有被子对象覆盖的区域,和子对象
在父子均实现IPointerDownHandler, IPointerUpHandler时,点击子对象覆盖住父对象的范围内时,只触发子对象的接口方法
------3.1.2 同级别下有遮挡时点击重和部分
同级别均实现IPointerDownHandler, IPointerUpHandler,UI物体有重和时,点击重和部分,仅触发最上层被点击到的UI对象的接口方法
补充一下:Hierarchy菜单,UI物体中越靠下的物体,才是越接近最上层的
---3.2 仅父对象实现 IPointerDownHandler, IPointerUpHandler (按钮是个特例)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestIEC : MonoBehaviour
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestIEP : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
public void OnPointerUp(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnPointerUp");
public void OnPointerDown(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnPointerDown");
仅父对象实现 IPointerDownHandler, IPointerUpHandler 时,点击子对象中的按钮仍无法触发父对象的接口方法(可以理解为按钮组件本身就有IPointer接口)依然覆盖掉了点击向父对象的传递。但点击到子对象中Image的一类本身不具有交互性的子对象,可以正常触发父对象的接口方法
---3.3 重合时仅下层实现 IPointerDownHandler, IPointerUpHandler (遮挡依然存在)
不论下层是否是按钮还是Image,点击重合部分,下层物体实现的接口方法都不会被触发
自然上下层都实现肯定只调用上层实现的接口方法
---3.4 只实现IPointerUpHandler时(无法正常被调用)
只实现IPointerUpHandler根本无法正常调用,必须实现IPointerDownHandler,才能正常传递,调用IPointerUpHandler的接口方法
---3.5 IPointerClickHandler(与3.1,3.2出现的情况类似)
参见3.1 和 3.2 测试结果类似,出现子对象覆盖,同级只触发最上层,以及按钮的特例覆盖效应
4.Drag/Drop 拖拽接口测试
先补充几点:
1. UI事件接口的onDrag方法 在开始拖动后,如果 中途停止拖动(不松开鼠标但不移动)不会被调用 ,而我们有测试过 onMouseDrag方法,开始拖动后即使中途拖动停止,依然会被调用
2.即使在极端状况下, IPointerDownHandler 也 一定会先于 IBeginDragHandler被调用
3.可以通过 eventData.pointerDrag.name 获取拖动启发的对象 ,并经常结合onDrop使用
4. IBeginDragHandler,IDragHandler,IEndDragHandler调用时均调用启发拖拽的物体 ,而 IDropHandler是拖拽到的物体 (结束拖拽是鼠标停留的物体)
5.通过 eventData.Dragging可以判断是否处于拖拽状态
---4.1 父子对象 均实现IBeginDragHandler,IDragHandler,IEndDragHandler,IDropHandler(依然有遮挡问题,跨层级拖拽正常)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestIEP : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler,IDropHandler
public void OnBeginDrag(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnBeginDrag");
public void OnDrag(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnDrag");
public void OnDrop(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnDrop"+" frmo:"+eventData.pointerDrag.name);
public void OnEndDrag(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnEndDrag");
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestIEC : MonoBehaviour,IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler
public void OnBeginDrag(PointerEventData eventData)
Debug.Log("C:" + gameObject.name + " OnBeginDrag");
public void OnDrag(PointerEventData eventData)
Debug.Log("C:" + gameObject.name + " OnDrag");
public void OnDrop(PointerEventData eventData)
Debug.Log("C:" + gameObject.name + " OnDrop" + " frmo:" + eventData.pointerDrag.name);
public void OnEndDrag(PointerEventData eventData)
Debug.Log("C:" + gameObject.name + " OnEndDrag");
父子对象 均实现IBeginDragHandler,IDragHandler,IEndDragHandler,IDropHandler时,注意遮挡问题,子对象对父对象的遮挡,重和部分的遮挡,以及onDrop一定先于endDrag调用。其他没有什么特别的地方
---4.2 仅父物体实现IBeginDragHandler,IDragHandler,IEndDragHandler,IDropHandler(这次谁也挡不住了)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestIEP : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler,IDropHandler
public void OnBeginDrag(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnBeginDrag");
public void OnDrag(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnDrag");
public void OnDrop(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnDrop"+" frmo:"+eventData.pointerDrag.name);
public void OnEndDrag(PointerEventData eventData)
Debug.Log("P:" + gameObject.name + " OnEndDrag");
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;