Unity UI event penetration

1.Event forwarding

Mounted on the UI, when clicked, the key event will be forwarded downward, core PassEvent, reference link

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System.Collections.Generic;
 
public class Test : MonoBehaviour,IPointerClickHandler ,IPointerDownHandler,IPointerUpHandler
{
    
     
 
    //监听按下
    public void OnPointerDown(PointerEventData eventData)
    {
    
    
        PassEvent(eventData,ExecuteEvents.pointerDownHandler);
    }
 
    //监听抬起
    public void OnPointerUp(PointerEventData eventData)
    {
    
    
        PassEvent(eventData,ExecuteEvents.pointerUpHandler);
    }
 
    //监听点击
    public void OnPointerClick(PointerEventData eventData)
    {
    
    
        PassEvent(eventData,ExecuteEvents.submitHandler);
        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);
                //RaycastAll后ugui会自己排序,如果你只想响应透下去的最近的一个响应,这里ExecuteEvents.Execute后直接break就行。
            }
        }
    }
}

2. Event non-interception (recommended)

The core is the unity interface ICanvasRaycastFilter

Reference Code:

using System;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
[RequireComponent(typeof(Button))]
[RequireComponent(typeof(RectTransform))]
public class GestureControl : MonoBehaviour, ICanvasRaycastFilter
{
    
    
    public bool NatureDestory = false;
    public bool Osmosis = true;
    public bool Strong = false;

    private bool _onceEnter = true;

    private Camera _uiCamera;

    private RectTransform tarRect;

    public event Action ClickEvent;

    public event Action InterruptEvent;

    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
    
    
        if (_uiCamera == null)
        {
    
    
            return false;
        }

        if (tarRect == null)
        {
    
    
            return true;//不渗透,遮罩
        }

        bool isContain = RectTransformUtility.RectangleContainsScreenPoint(tarRect, sp, _uiCamera);
        if (isContain)
        {
    
    
            if (Input.GetMouseButtonUp(0) && _onceEnter)
            {
    
    
                _onceEnter = false;
                NatureDestory = true;

                //按下事件,销毁遮罩自身,需要避免多次销毁
                GameObject.Destroy(this.gameObject, 0.1f);
            }
            return false;
        }

        return true;//不渗透,遮罩
    }

    private void OnDestroy()
    {
    
    
        if (ClickEvent != null)
        {
    
    
            ClickEvent();
        }
        if (!NatureDestory)
        {
    
    
            //非点击自然销毁,调用中断
            Debug.Log("非自然中断");
            InterruptEvent();
        }
    }

    // Start is called before the first frame update
    private void Start()
    {
    
    
        tarRect = this.GetComponent<RectTransform>();
        this.GetComponent<ParticleSystem>().Play();

        var cameras = GameObject.FindObjectsOfType<Camera>();
        _uiCamera = cameras.Where(p => p.name == "UICamera").First();
        //是否强制引导
    }
}

3.UiFilter two kinds of penetration together

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
[RequireComponent(typeof(Button))]
[RequireComponent(typeof(RectTransform))]
public class UiFilter : MonoBehaviour, ICanvasRaycastFilter, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler
{
    
    
    public bool NatureDestory = false;
    public bool Osmosis = true;
    public bool Strong = false;
    public bool isTransOsmosis = true;//是转发型渗透

    private bool _onceEnter = true;

    private Camera _uiCamera;

    private RectTransform tarRect;

    public event Action ClickEvent;

    public event Action InterruptEvent;

    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
    
    
        //是否强制引导指定位置
        if (isTransOsmosis)
        {
    
    
            return true;
        }
        if (_uiCamera == null)
        {
    
    
            return true;
        }

        if (tarRect == null)
        {
    
    
            return true;
        }

        bool isContain = RectTransformUtility.RectangleContainsScreenPoint(tarRect, sp, _uiCamera);
        if (isContain)
        {
    
    
            if (Input.GetMouseButtonDown(0) && _onceEnter)
            {
    
    
                _onceEnter = false;
                NatureDestory = true;

                //按下事件,销毁遮罩自身,需要避免多次销毁
                GameObject.Destroy(this.gameObject, 0.1f);
            }
            return false;//渗透
        }

        return true;//不渗透
    }

    private void OnDestroy()
    {
    
    
        if (ClickEvent != null)
        {
    
    
            ClickEvent();
        }
        if (!NatureDestory)
        {
    
    
            //非点击自然销毁,调用中断
            Debug.Log("非自然中断");
            InterruptEvent();
        }
    }

    // Start is called before the first frame update
    private void Start()
    {
    
    
        tarRect = this.GetComponent<RectTransform>();
        this.GetComponent<ParticleSystem>().Play();

        var cameras = GameObject.FindObjectsOfType<Camera>();
        _uiCamera = cameras.Where(p => p.name == "UICamera").First();
        //是否强制引导

        if (isTransOsmosis)
        {
    
    
            var button= this.GetComponent<Button>();
            button.onClick.AddListener(ButtonClick);
        }
    }

    private void ButtonClick()
    {
    
    
        if (_onceEnter)
        {
    
    
            _onceEnter = false;
            NatureDestory = true;

            //按下事件,销毁遮罩自身,需要避免多次销毁
            GameObject.Destroy(this.gameObject, 0.1f);
        }
    }

    //点击渗透
    public void OnPointerClick(PointerEventData eventData)
    {
    
    
        if (Osmosis)
        {
    
    
            PassEvent(eventData, ExecuteEvents.pointerClickHandler);
        }
    }

    //按下渗透
    public void OnPointerDown(PointerEventData eventData)
    {
    
    
        if (Osmosis)
        {
    
    
            PassEvent(eventData, ExecuteEvents.pointerDownHandler);
        }
    }

    //抬起渗透
    public void OnPointerUp(PointerEventData eventData)
    {
    
    
        if (Osmosis)
        {
    
    
            PassEvent(eventData, ExecuteEvents.pointerUpHandler);
        }
    }

    public void PassEvent<T>(PointerEventData data, ExecuteEvents.EventFunction<T> function)
        where T : IEventSystemHandler
    {
    
    
        var parent = transform.parent.gameObject;
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(data, results);
        GameObject current = data.pointerCurrentRaycast.gameObject;
        for (int i = 0; i < results.Count && i < 5; i++)//渗透不能太多,防卡死
        {
    
    
            if (current != results[i].gameObject && parent != results[i].gameObject)
            {
    
    
                ExecuteEvents.Execute(results[i].gameObject, data, function);
                //RaycastAll后ugui会自己排序,如果你只想响应透下去的最近的一个响应,这里ExecuteEvents.Execute后直接break就行。
                break;
            }
        }

        ExecuteEvents.Execute(parent, data, function);
    }
}

4.UnityUI comes with penetration

Uncheck Raycast Target

file

Guess you like

Origin blog.csdn.net/euphorias/article/details/127060714