Unity uGUI原理解析

Unity uGUI原理解析

Unity uGUI 是Unity官方推出的UI解决方案。 以Package的方法在Unity中提供。官方参考手册 API参考

Unity uGUI的使用可以参考超详细的Unity UGUI教学

准备工作

由于UGUI是Untiy提供的核心包,为了能够看到看到及调试源码。 需要在 Preferences -> External Tools -> Generate .csproj file for: 中勾选 Built-in packages. 重新生成后就可以在Visual Studio 中看到 UnityEngine.UI项目。到这里就可以正常使用附加到Unity功能来进行UGUI代码的调试工作。

使用 Visual Studio 的查看类图功能我们可以看到UnityEngine.UI的类图。生成类图可参考VS 代码结构自动生成类图.

具体类图大概如下(Unity版本2019.4.20):
在这里插入图片描述

类图分析

从类图上可以看出UGUI中UI组件的基类为 UIBehaviour。 而UI组件大致可以分成:

UGUI原理

在UGUI中,UI的组成大致就是界面和事件。
在创建UI时会自动生成 Canvas 以及 EventSystem, 这两个就对应界面以及事件。这里的 EventSystem 通常还会和 Input Module 一起出现。

EventSystem 继承自 UIBehaviour, 我们可以看到在OnEnable的时候将自身添加到m_EventSystems这个静态变量中, 而在OnDisable的时候将自身从m_EventSystems移除。 这个步骤的目的是为了在 Update 中判断 current 是否为自身。 就是说如果存在多个EventSystem 组件则只会有一个触发Update中的内容。

在Update的最末尾,经过一系列的判断后会调用InputModule的Process方法。

public class EventSystem : UIBehaviour
{
    
    
	//...
	protected override void OnEnable()
	{
    
    
	    base.OnEnable();
	    m_EventSystems.Add(this);
	}
	
	protected override void OnDisable()
	{
    
    
	    if (m_CurrentInputModule != null)
	    {
    
    
	        m_CurrentInputModule.DeactivateModule();
	        m_CurrentInputModule = null;
	    }
	
	    m_EventSystems.Remove(this);
	
	    base.OnDisable();
	}
    protected virtual void Update()
    {
    
    
        if (current != this)
            return;
        TickModules(); // <<--  在这里触发 InputModule 的 UpdateModule 方法
		
		//...
       	if (!changedModule && m_CurrentInputModule != null)
			m_CurrentInputModule.Process(); // <<-- 在这里进行输入的处理
    }
	//...
}

InputModule 有 PointerInputModule, StandaloneInputModule, TouchInputModule, 这些类都继承自BaseInputModule。

这里以StandaloneInputModule为例, 其中的 Process 函数就是在EventSystem中Update里面调用的方法。在这当中还会调用 ProcessMouseEvent 来处理鼠标事件。而在处理事件之前我们还需要知道点击了那个组件。 所以GetMousePointerEventData中还会调用 EventSystem.RaycastAll 来对继承自BaseRaycaster 的组件进行射线检测。

public class StandaloneInputModule : PointerInputModule
{
    
    
	//...
    public override void Process()
    {
    
    
        if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
            return;
        // ...
        // touch needs to take precedence because of the mouse emulation layer
        if (!ProcessTouchEvents() && input.mousePresent)
            ProcessMouseEvent(); // 处理鼠标事件
        // ...
    }
	/// <summary>
    /// Process all mouse events.
    /// </summary>
    protected void ProcessMouseEvent(int id)
    {
    
    
        var mouseData = GetMousePointerEventData(id); // << 在这里面会调用 EventSystem.RaycastAll 来执行射线检测
		//...
    }
}

总结:EventSystem主要就是通过输入模块(InputModule)对所有的需要被检测的对象(BaseRaycaster)进行检测。 通常我们看到的是 GraphicRaycaster (和Canvas挂载在统一游戏对象上)来进行射线检测。 然后再通过GraphicRaycaster调用每一个实现了ICanvasRaycastFilter接口的Graphic(也就是RawImage、Image、Text)。

猜你喜欢

转载自blog.csdn.net/qq_36433883/article/details/125444197