前言
尽量用最简单易懂的文字说明。因为自己也是个菜鸡,所以会用菜鸡也听得懂的话来说。
思路是先看父类,然后一层一层下去,中间遇到没见过的类就点进去看一下。
源码下载地址
https://bitbucket.org/Unity-Technologies/ui/downloads/?tab=downloads
UIBehaviour
一切UI组件的父类。叫爸爸。
是一个抽象类,定义了一堆虚方法,以及实现了唯一的一个实方法IsDestroyed()
。
**除了**unity本身的几个生命周期方法之外,还定义了几个值得注意的虚方法:
- OnRectTransformDimensionsChange()
- OnBeforeTransformParentChanged()
- OnTransformParentChanged()
- OnDidApplyAnimationProperties()
- OnCanvasGroupChanged()
* OnCanvasHierachyChanged()
Graphic
可视元件之祖。
要求一定要有CanvasRenderer和RectTransform这两个组件。
话说起来CanvasRenderer是啥?
这个东西属于UnityEngine命名空间的,提供了一些可视的方法比如:
- Get/SetMaterial
- Get/SetAlpha
- Get/SetColor
- SetMesh
- SetTexture
Fields
- 有一个public static的默认材质,从canvas里面取,就是空材质的意思了。
- 颜色,默认是白色
- 是否为rayCastTarget,布尔值
- 当然,要有上述两个必须的部件为私有域,还要持有一个Canvas(不知为何)
- 两个dirty标志位,一个是verts,一个是material;三个dirtyCallback:layout, verts, material。
- 一个静态的Mesh(不知何用)
Methods
- 构造方法是protected的,不能外部调用。
新建并初始化了一个ColorTweenRunner,现在还不知道干啥用的。 - 几个SetDirty方法
做各自的逻辑,并执行对应的callback(如果有的话)
- SetLayoutDirty
设置标志位并执行:
csharp
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
这里注意LayoutRebuilder。把自己标志位需要布局重绘。 - SetVerticesDirty
设置标志位并执行:
csharp
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
同样这里注意CanvasUpdateRegistry,据我看cocos2dx代码的经验,这里应该是说注册了下一帧update的时候,来更新顶点。
进去一看,就是把这个ICanvasElement给放到队列里面去,这个队列名字叫m_GraphicRebuildQueue
- SetMaterialDirty
csharp
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
应该是重绘的意思,设置了material之后就会执行这个方法。
- SetLayoutDirty
- OnBeforeTransformParentChanged
从canvas上解除自己的监听,然后要求layoutRebuild。 - OnTransformParentChanged
CacheCanvas,重新绑定到canvas(before的时候取消注册了)
GraphicRegistry.RegisterGraphicForCanvas(canvas, this);
然后设置所有dirty。
CacheCanvas()
从gameObject取出Canvas列表,然后把第一个设置为m_Canvas
。
所以这里又有一个问题,为啥graphic身上会有一个canvas??
分割线~~~
既然这么多次提到了GraphicRegistry. RegisterGraphicForCanvas(Canvas, Graphic)
看了一下,做了啥呢。从instance.m_Graphics里面以canvas为key取出一个IndexSet,然后把graphic添加进去。如果木有这个队列,就创建这个队列然后塞进去。
于是 下一个问题就是:这个队列干嘛用的呢?
首先这个字典是private readonly的,用处有三个方法,一个注册,一个注销,以及一个取出来的方法
GetGraphicsForCanvas(Canvas canvas)
(全局搜索发现这个方法被GraphicRaycaster.Raycast()用到啦~非常好)。
所以说这一切都是为了Raycast!!只是为了射线检测而已!! 这样子的话不会很蠢吗!!!!
- OnEnable
把canvas缓存起来,然后注册自身到canvas。最后SetAllDirty()。 - OnDisable
GraphicRegistry.UnregisterGraphicForCanvas(canvas, this);
CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
- 注销canvas
- 不需要update了
- canvasRenderer.Clear() 啥意思呢?
> Remove all cached vertices.
- 因为disable了,要消失了,所以叫布局可以重新布局啦~
`LayoutRebuilder.MarkLayoutForRebuild(rectTransform);`
所以要看一下这个LayoutRebuilder究竟怎么实现重绘的,应该最后会execute到具体某个layout上面去。
另外,要明确一下顶点的概念。清除顶点又是啥意思?
OnCanvasHierarchyChanged
把自己从原来的canvas给注销掉,然后注册到新的canvas。Rebuild
不知道干啥用的UpdateMaterial
调用canvasRenderer的SetMaterial和SetTexture,说明实际上绘制是在CanvasRenderer。UpdateGeometry
以及他所调用的DoMeshGeration和DoLegacyMeshGeneration都是改变顶点的,先不看。OnPopulateMesh
似乎和Mesh有关系,Image里面也会有,这里先不看了。Raycast
这是重头戏了,关于射线检测啥的,这里先不看。里面会调用ICanvasRaycastFilter接口,看看有没有被射到,有兴趣先看的同学,去看一下Image的实现。CrossFadeColor
颜色渐变,没兴趣看。