NGUI源码剖析之UIRect

UIRect是一个代表UI矩形区的抽象类。一个矩形区有上、下、左、右四边,因此UIRect中有4个锚点分别指示这四边anchor的位置:
public AnchorPoint leftAnchor = new AnchorPoint();
public AnchorPoint rightAnchor = new AnchorPoint(1f);
public AnchorPoint bottomAnchor = new AnchorPoint();
public AnchorPoint topAnchor = new AnchorPoint(1f);

有bottom-left、top-left、top-right、bottom-right四个角:
public abstract Vector3[] localCorners { get; }
public abstract Vector3[] worldCorners { get; }

每个矩形区是一个UI的容器,因此UIRect可以组成一个树状结构:
BetterList<UIRect> mChildren即孩子节点列表,OnInit、OnDisable及ParentHasChanged时将进行动态的Add和Remove。
UIRect mParent即父节点,会从该UIRect绑定的GameObject进行回溯寻找,bool mParentFound表示其有没有进行过回溯寻找。

NGUI中UIRoot是所有UI对象的根节点,UIRect中的UIRoot mRoot就指向了该节点,bool mRootSet表示其有没有进行过回溯寻找。

UIRect里为了加速访问绑定的GameObject及其Transform做了缓存:
protected GameObject mGo;
protected Transform mTrans;
public GameObject cachedGameObject { get { if (mGo == null) mGo = gameObject; return mGo; } }
public Transform cachedTransform { get { if (mTrans == null) mTrans = transform; return mTrans; } }

Camera mMyCam为负责渲染UIRect绑定的GameObject这一层的Camera,bool mAnchorsCached表示其以及4个锚点的数据有没有设置好。
bool mStarted:UnityEngine是否回调了Start方法
bool mChanged:父对象中有值(如alpha)改变时将其设置为true,用于刷新表现。
int mLastInvalidate:通过Time.frameCount记录下最后调用Invalidate的帧数。
int mUpdateFrame:通过Time.frameCount记录已经Update过的帧数。

UIRect中的主要功能在Update里:
1、通过mAnchorsCached判断是否需要更新锚点的相关数据,需要则通过ResetAnchors来更新数据。
2、通过mUpdateFrame与Time.frameCount判断该帧是否已经经过Update处理,处理过则本次Update结束了。
3、分别判断4个锚点是否有设置,有的话则判断该锚点的rect是否已经经过Update处理,未处理过则调用其Update方法。
4、判断4个锚点是否至少有1个有设置,则调用OnAnchor方法。
5、调用OnUpdate方法继续处理。
OnAnchor和OnUpdate方法均是抽象方法,需要由UIRect的子类自己来实现:
protected abstract void OnAnchor ();
protected virtual void OnUpdate () { }

NGUI源码剖析之UIRect.AnchorPoint

AnchorPoint(锚点)用于定位对象相对于目标对象在水平或垂直方向的位置。
Transform target即目标对象。
UIRect rect即目标对象上绑定的UIRect组件,可能为null。
Camera targetCam为负责渲染目标对象这一层的Camera。
int absolute为对象相对于目标对象在水平或垂直方向的偏移量。
float relative有三个取值0f、0.5f、1f。
锚点应用于UIRect中,UIRect中有上、下、左、右4个锚点分别用于定位其四条边的位置。
若目标对象无对应的UIRect时,目标对象的位置即其中心点的位置(target.position)。水平方向计算其与leftAnchor的偏移时会先通过对对象UIRect的worldCorners[0](bottom-left corner)和worldCorners[1](top-left corner)进行线性插值计算出UIRect的左边中心点,这两个中心点的x差值即偏移量。
若目标对象有对应的UIRect时,锚点定位对象相对于目标对象水平方向的位置时分为left、center和right对齐,垂直方向则分为top、center和bottom对齐。这种情况下在Unity编辑器中设置好一个锚点后,可以随时在left/center/right和top/center/bottom间切换,NGUI会保持对象的位置并且动态计算出新的对齐方式下对象与目标对象的偏移量。
参考文章:Explanation Local Vs Global Space

NGUI源码剖析之UIRoot

UIRoot脚本绑定的GameObject是NGUI里所有UI对象的根节点,脚本本身的作用是将根节点保持缩放到2/(Screen.height)的大小。
由于Unity中对父对象进行缩放会同时对其子对象做相应的缩放,因此NGUI用UIRoot控制对整个UI的缩放以适配不同屏幕的宽高比。
UIRoot有3种缩放模式:
public enum Scaling
{
PixelPerfect,
FixedSize,
FixedSizeOnMobiles,
}
PixelPerfect模式是当屏幕高度在minimumHeight和maximumHeight区间时不进行缩放。
FixedSize模式是只有屏幕高度为manualHeight时才不进行缩放。
FixedSizeOnMobiles模式与FixedSize模式无异,只是通过UNITY_IPHONE和UNITY_ANDROID宏区分该模式是否能生效。
参考文章:Unity3D开发(一):NGUI之UIRoot屏幕分辨率自适应
不同屏幕高度下的缩放比可以通过GetPixelSizeAdjustment函数获取:
public float GetPixelSizeAdjustment (int height)
{
height = Mathf.Max(2, height);

if (scalingStyle == Scaling.FixedSize)
return (float)manualHeight / height;

#if UNITY_IPHONE || UNITY_ANDROID
if (scalingStyle == Scaling.FixedSizeOnMobiles)
return (float)manualHeight / height;
#endif
if (height < minimumHeight) return (float)minimumHeight / height;
if (height > maximumHeight) return (float)maximumHeight / height;
return 1f;
}
缩放后的高度应为:Resource’s height / GetPixelSizeAdjustment(Screen.height)
UIRoot中有一个静态列表用于管理处于enable状态下的所有UIRoot对象,并提供了Broadcast方法。