序言:

关于UnityUGUI系统还是挺复杂,这里记录一下平常遇到的问题。

正文:

UI世界坐标系和屏幕坐标系的统一

接触过U3D的同学都知道当我们在项目中新建UI对象时,都会在创建在名为Canvas的对象下,如下图

unity ui怎么调层级_unity ui怎么调层级

这几天在工作中遇到一个问题,就是 UI跟随鼠标运动,本来使用的是以下程序:

var x = Mathf.Clamp(Input.mousePosition.x, 0, Screen.width);
            var y = Mathf.Clamp(Input.mousePosition.y, 0, Screen.height);
            transform.position = new Vector3(x, y, 0);

后来更新代码想到Input.mousePosition是屏幕坐标,而transform.position是世界坐标系,我这样直接赋值会不会发生坐标错误。后来发现其实系统为我们创建的Canvas其实已经自动完成了UI世界坐标系和屏幕坐标系的转换。

unity ui怎么调层级_Image_02

当我在Game视图下改变屏幕大小时,我发现Canvas的长宽始终是固定的,随着屏幕实际尺寸变化的是Scale属性。并且我尝试在Game视图下改变屏幕大小时,打印出Canvas的实际尺寸和屏幕的实际尺寸:

void Update()
    {
        var canvas = GameObject.Find("Canvas").GetComponent<RectTransform>();
        Debug.Log("屏幕尺寸:"+Screen.width+"  "+Screen.height+";"+
                  "Canvas尺寸: "+canvas.rect.width*canvas.localScale.x+"  "+ 
                   canvas.rect.height * canvas.localScale.y);
    }

unity ui怎么调层级_U3D_03

可以看出,无论我如何改变Game窗口的大小,Canvas的实际尺寸和屏幕的实际大小都是一致的。说明Unity在Canvas这里帮我们完成了屏幕坐标系和UI世界坐标系的转换。

 

UGUI Button的交互

Unity UGUI点击响应的必要条件是至少本身或者子对象有Graphic子类组件处于激活状态并且Raycast Target属性为真,而且需要获取事件对象的子对象会获取事件并将事件传递给父对象。

unity ui怎么调层级_UI_04

测试:

unity ui怎么调层级_Image_05

 

首先,我们在项目中新建三个Image对象,并分别命名为Button、Child、Other,为Button对象添加Button组件,将Child设置为Button的子对象,并让Other大小与Button大小一致,并正好挡在Button的前面。为了后期观察分别将三个对象设置为白色、黑色、半透明白色。

button.onClick.AddListener(delegate { Debug.Log("Click"); });

属性设置:

 

激活

Image激活

Raycast Target

Button

true

true

true

Child

true

true

true

Other

true

true

true

 

结果:

unity ui怎么调层级_世界坐标系_06

证明与Button处于兄弟节点关系,层级在Button对象之前且RaycastTarget属性为真的对象会挡住Button获取点击事件。

 

属性设置:

 

激活

Image激活

Raycast Target

Button

true

true

true

Child

true

true

true

Other

true

true

false

 

结果:

unity ui怎么调层级_UI_07

证明RaycastTarget属性为真对象会截获点击事件并组织事件向下传递。

 

属性设置:

 

激活

Image激活

Raycast Target

Button

true

true

true

Child

true

true

true

Other

true

false

true

 

结果:

unity ui怎么调层级_UI_08

证明UI对象获取事件依赖于Graphic类组件,并且Button子对象并不会截取父对象的时间获取。

 

属性设置:

 

激活

Image激活

Raycast Target

Button

true

false

true

Child

true

true

true

Other

false

true

true

结果:

unity ui怎么调层级_世界坐标系_09

点击在Child对象渲染区域上仍旧会有事件响应,说明子对象会帮助父对象获取事件并将事件传递给父对象。

 

综上,Unity UGUI点击响应的必要条件是至少本身或者子对象有Graphic子类组件处于激活状态并且Raycast Target属性为真,而且需要获取事件对象的子对象会获取事件并将事件传递给父对象。