一 , Scene设计
Ⅰ, A和B是兄弟
Ⅱ, C是A的孩子
二, 测试一(穿透测试)
Ⅰ, 代码
A , B , C 分别挂载A.cs , B.cs , C.cs , 分别如下
A.cs 代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class A : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("A click");
}
}
B.cs 代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class B : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("B click");
}
}
C.cs 代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class C : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("C click");
}
}
Ⅱ, 测试
A, 卸载 B 和 C的脚本 B.cs 和 C.cs
1, 点击C的时候A会触发事件
2, 点击B的时候A不会触发事件(兄弟拦截了)
B, 将B 和 C 的 脚本B.cs 和 C.cs重新挂载到B,C上
1, 点击C的时候A不会触发事件(被C拦截了)
2, 和上面一样点击B,A也不会触发事件
结论:
①,无论兄弟是否挂载了脚本,都会拦截处于下方得其他兄弟的事件
②,孩子级别比较特殊, 如果孩子挂载脚本,就会拦截父方脚本;反之则不会拦截
三, 测试二(传递测试)
1, 特殊需求: 无论点击B或者C都会触发下面的A
B.cs 代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class B : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("B click");
PassEvent(eventData, ExecuteEvents.pointerClickHandler);
}
//把事件透下去
public void PassEvent<T>(PointerEventData data, ExecuteEvents.EventFunction<T> function)
where T : IEventSystemHandler
{
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(data, results);
GameObject current = data.pointerCurrentRaycast.gameObject;
for (int i = 0; i < results.Count; i++)
{
if (current != results[i].gameObject)
{
ExecuteEvents.Execute(results[i].gameObject, data, function);
}
}
}
}
C.cs 代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class C : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("C click");
PassEvent(eventData, ExecuteEvents.pointerClickHandler);
}
public void PassEvent<T>(PointerEventData data, ExecuteEvents.EventFunction<T> function)
where T : IEventSystemHandler
{
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(data, results);
GameObject current = data.pointerCurrentRaycast.gameObject;
for (int i = 0; i < results.Count; i++)
{
if (current != results[i].gameObject)
{
ExecuteEvents.Execute(results[i].gameObject, data, function);
}
}
}
}
四, 需求:B不需要Event, 但是要透过B可以触发A的Event
1, 脚本
using UnityEngine;
using UnityEngine.UI;
public class ImageExtends : Image
{
override public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
return false;//不拦截, (自己也不会触发Event)
}
}
2, 将脚本挂载到B的GameObject上
五, 需求: 关闭A及A的孩子的Event
1, A.cs 继承 ICanvasRaycastFilter
2, 重写 IsRaycastLocationValid() 方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class A : MonoBehaviour, IPointerClickHandler, ICanvasRaycastFilter
{
[SerializeField]
private bool IsFocus = false;
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("A click");
}
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
return IsFocus;
}
}
当 IsFocus 为false 时, A,C不触发Event