UGUI事件解析

简述

最简单的说就是,EventSystem在每帧去input看有没有数据,有的话就对每条数据都遍历所有canvas下的所有graphics,找出所有命中的graphics,选择第一个graphic的gameobject,执行go对应的component的事件处理函数。高度概括伪代码如下:

EventSystem.Update()
	// 查看当前是否有输入,如n点触控,touchCount=n (以touch事件处理为例)
    for (int i = 0; i < Input.touchCount; i++) 
    {
        List<Graphic> hitResults = new List<Graphic>();
        for (int j = 0; j < canvasCount; j++)
        {
            List<Graphic> graphicsList = canvasList[j].graphics;
            for (int z = 0; z < graphicsList.Count; z++)
            {
                Graphic graphic = graphicsList[z];
                if (isHit)
                {
                    hitResults.Add(graphic);
                }
            }
        }
        Graphic First = hitResults[0];
        GameObject go = First.gameObject;
        // 找出go下实现了对应事件的Component,执行其对应回调,如: OnPointerDown
        // 根据父子层级关系,构建执行对应的事件链,一直往下穿,直接有Component处理为止
        t = go.transform
        while (t != null)
            {
                eventChain.Add(t);
                t = t.parent;
            }
		for(int i=0;i < eventChain.Count; i++){
            // 找出gameobject实现了IPointerDownHandler的Component
            list<IPointerDownHandler> pList= eventChain[i].GetComponents<IPointerDownHandler>()
                for(int j = 0; j<pList.count; p++){
		            //执行回调
                }
            //有执行就直接返回
            if (pList.count > 0) return
        }
    }

事件类结构

img

时序图

img

建议

  1. 如若能确定此canvas下的UI不需要响应事件,则可以直接在canvas中去掉GraphicsRaycast组件:
  2. Image/Text挂的GameObject不需要响应事件时,应把Raycast Target选项去掉,特别是Button类,会带一个Image(背景图)和Text(按钮文字),应把Text的Raycast Target去掉:
  3. 事件不会透穿,即事件只会被一个GameObject消费掉:
  4. 执行链会往上查找执行,意味着:如果一个gameobject有一个子gameObject,子gameobject挂了一个Image,如果事件没有被子gameobject处理,那么会往上穿,即使子gameobject的“矩形”不在其父gameobject里。

考虑的优化点:不用canvas的graphics管理,业务层直接将关心的事件注册到EventSystem中,但原生事件相关的东西就不能用了,根据性能考虑是否做这个优化。

原文地址:https://www.cnblogs.com/quehualin/p/13587107.html