Graphic:是UGUI的核心组件,负责图对象的显示和更新,是MaskableGraphic的基类,而MaskableGraphic是Text、RawImage、Image的基类。Graphic是一个抽象类,意味着不能被实例化,但是它提供了很多可重写的方法可被继承并重写。
源码解析
类头:特性,Graphic是继承自UIBehaviour和ICanvasElement,UIBehaviour是所有UGUI组件的最基类,负责接收UnityEditor的事件。ICanvasElement负责接收Canvas重新渲染的事件。
UGUI源码解析——UIBehaviour
UGUI源码解析——CanvasUpdateRegistry
1 2 3 4 5 6 7 8 [DisallowMultipleComponent ] [RequireComponent(typeof(CanvasRenderer)) ] [RequireComponent(typeof(RectTransform)) ] [ExecuteAlways ]
字段
UGUI源码解析——SetPropertyUtility
SetPropertyUtility:设置UI元素属性的静态工具类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 static protected Material s_DefaultUI = null ;static public Material defaultGraphicMaterial{ get { if (s_DefaultUI == null ) s_DefaultUI = Canvas.GetDefaultCanvasMaterial(); return s_DefaultUI; } } public virtual Material defaultMaterial{ get { return defaultGraphicMaterial; } } static protected Texture2D s_WhiteTexture = null ;public virtual Texture mainTexture{ get { return s_WhiteTexture; } } [FormerlySerializedAs("m_Mat" ) ] [SerializeField ] protected Material m_Material; public virtual Material material{ get { return (m_Material != null ) ? m_Material : defaultMaterial; } set { if (m_Material == value ) return ; m_Material = value ; SetMaterialDirty(); } } [SerializeField ] private Color m_Color = Color.white; public virtual Color color { get { return m_Color; } set { if (SetPropertyUtility.SetColor(ref m_Color, value )) SetVerticesDirty(); } }[NonSerialized ] protected bool m_SkipLayoutUpdate; [NonSerialized ] protected bool m_SkipMaterialUpdate; [SerializeField ] private bool m_RaycastTarget = true ; public virtual bool raycastTarget { get { return m_RaycastTarget; } set { m_RaycastTarget = value ; } }[NonSerialized ] private RectTransform m_RectTransform; public RectTransform rectTransform{ get { if (ReferenceEquals(m_RectTransform, null )) { m_RectTransform = GetComponent<RectTransform>(); } return m_RectTransform; } } [NonSerialized ] private CanvasRenderer m_CanvasRenderer; public CanvasRenderer canvasRenderer{ get { if (ReferenceEquals(m_CanvasRenderer, null )) { m_CanvasRenderer = GetComponent<CanvasRenderer>(); } return m_CanvasRenderer; } } [NonSerialized ] private Canvas m_Canvas; public Canvas canvas{ get { if (m_Canvas == null ) CacheCanvas(); return m_Canvas; } } [NonSerialized ] private bool m_VertsDirty; [NonSerialized ] private bool m_MaterialDirty; [NonSerialized ] protected UnityAction m_OnDirtyLayoutCallback; [NonSerialized ] protected UnityAction m_OnDirtyVertsCallback; [NonSerialized ] protected UnityAction m_OnDirtyMaterialCallback; [NonSerialized ] protected static Mesh s_Mesh; protected static Mesh workerMesh{ get { if (s_Mesh == null ) { s_Mesh = new Mesh(); s_Mesh.name = "Shared UI Mesh" ; s_Mesh.hideFlags = HideFlags.HideAndDontSave; } return s_Mesh; } } [NonSerialized ] private static readonly VertexHelper s_VertexHelper = new VertexHelper(); [NonSerialized ] protected Mesh m_CachedMesh; [NonSerialized ] protected Vector2[] m_CachedUvs; private readonly TweenRunner<ColorTween> m_ColorTweenRunner;protected bool useLegacyMeshGeneration { get ; set ; }public int depth { get { return canvasRenderer.absoluteDepth; } }public virtual Material materialForRendering{ get { var components = ListPool<Component>.Get(); GetComponents(typeof (IMaterialModifier), components); var currentMat = material; for (var i = 0 ; i < components.Count; i++) currentMat = (components[i] as IMaterialModifier).GetModifiedMaterial(currentMat); ListPool<Component>.Release(components); return currentMat; } }
构造函数:创建一个颜色变化的插值对象,并将当前实例传递。指定图形组件在初始化时使用旧版网格生成方式。
1 2 3 4 5 6 7 protected Graphic (){ if (m_ColorTweenRunner == null ) m_ColorTweenRunner = new TweenRunner<ColorTween>(); m_ColorTweenRunner.Init(this ); useLegacyMeshGeneration = true ; }
SetAllDirty:设置所有的图形属性需要进行重建,如布局,顶点,材质等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public virtual void SetAllDirty (){ if (m_SkipLayoutUpdate) { m_SkipLayoutUpdate = false ; } else { SetLayoutDirty(); } if (m_SkipMaterialUpdate) { m_SkipMaterialUpdate = false ; } else { SetMaterialDirty(); } SetVerticesDirty(); }
SetLayoutDirty:将布局设置为脏,需要进行布局重建
1 2 3 4 5 6 7 8 9 10 11 12 public virtual void SetLayoutDirty (){ if (!IsActive()) return ; LayoutRebuilder.MarkLayoutForRebuild(rectTransform); if (m_OnDirtyLayoutCallback != null ) m_OnDirtyLayoutCallback(); }
SetVerticesDirty:将顶点设置为脏,需要进行布局重建
1 2 3 4 5 6 7 8 9 10 11 12 13 public virtual void SetVerticesDirty (){ if (!IsActive()) return ; m_VertsDirty = true ; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this ); if (m_OnDirtyVertsCallback != null ) m_OnDirtyVertsCallback(); }
SetMaterialDirty:将材质设置为脏,需要进行布局重建
1 2 3 4 5 6 7 8 9 10 11 12 public virtual void SetMaterialDirty (){ if (!IsActive()) return ; m_MaterialDirty = true ; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this ); if (m_OnDirtyMaterialCallback != null ) m_OnDirtyMaterialCallback(); }
OnRectTransformDimensionsChange:当RectTransform尺寸发生变化的时候调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 protected override void OnRectTransformDimensionsChange (){ if (gameObject.activeInHierarchy) { if (CanvasUpdateRegistry.IsRebuildingLayout()) SetVerticesDirty(); else { SetVerticesDirty(); SetLayoutDirty(); } } }
OnBeforeTransformParentChanged:父对象变更前调用
1 2 3 4 5 6 7 protected override void OnBeforeTransformParentChanged (){ GraphicRegistry.UnregisterGraphicForCanvas(canvas, this ); LayoutRebuilder.MarkLayoutForRebuild(rectTransform); }
OnTransformParentChanged:父对象发生变化的时候调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected override void OnTransformParentChanged (){ base .OnTransformParentChanged(); m_Canvas = null ; if (!IsActive()) return ; CacheCanvas(); GraphicRegistry.RegisterGraphicForCanvas(canvas, this ); SetAllDirty(); }
CacheCanvas:缓存当前对象的第一个Canvas父对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private void CacheCanvas (){ var list = ListPool<Canvas>.Get(); gameObject.GetComponentsInParent(false , list); if (list.Count > 0 ) { for (int i = 0 ; i < list.Count; ++i) { if (list[i].isActiveAndEnabled) { m_Canvas = list[i]; break ; } } } else { m_Canvas = null ; } ListPool<Canvas>.Release(list); }
OnEnable:将图形和画布设置为脏标记
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected override void OnEnable () { base .OnEnable(); CacheCanvas(); GraphicRegistry.RegisterGraphicForCanvas(canvas, this ); #if UNITY_EDITOR GraphicRebuildTracker.TrackGraphic(this ); #endif if (s_WhiteTexture == null ) s_WhiteTexture = Texture2D.whiteTexture; SetAllDirty(); }
OnDisable:清空引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 protected override void OnDisable () { #if UNITY_EDITOR GraphicRebuildTracker.UnTrackGraphic(this ); #endif GraphicRegistry.UnregisterGraphicForCanvas(canvas, this ); CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this ); if (canvasRenderer != null ) canvasRenderer.Clear(); LayoutRebuilder.MarkLayoutForRebuild(rectTransform); base .OnDisable(); }
OnDestroy:清空网格引用
1 2 3 4 5 6 7 8 protected override void OnDestroy (){ if (m_CachedMesh) Destroy(m_CachedMesh); m_CachedMesh = null ; base .OnDestroy(); }
OnCanvasHierarchyChanged:Canvas的层级发生变化的时候调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 protected override void OnCanvasHierarchyChanged (){ Canvas currentCanvas = m_Canvas; m_Canvas = null ; if (!IsActive()) return ; CacheCanvas(); if (currentCanvas != m_Canvas) { GraphicRegistry.UnregisterGraphicForCanvas(currentCanvas, this ); if (IsActive()) GraphicRegistry.RegisterGraphicForCanvas(canvas, this ); } }
OnCullingChanged:处理 Canvas 元素在被剔除状态变化时的逻辑
1 2 3 4 5 6 7 8 9 public virtual void OnCullingChanged (){ if (!canvasRenderer.cull && (m_VertsDirty || m_MaterialDirty)) { CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this ); } }
Rebuild:根据 CanvasUpdate
类型重新构建图形组件,确保在绘制之前,组件的几何体和材质都是最新的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public virtual void Rebuild (CanvasUpdate update ){ if (canvasRenderer == null || canvasRenderer.cull) return ; switch (update) { case CanvasUpdate.PreRender: if (m_VertsDirty) { UpdateGeometry(); m_VertsDirty = false ; } if (m_MaterialDirty) { UpdateMaterial(); m_MaterialDirty = false ; } break ; } }
LayoutComplete:布局重建完成事件
1 public virtual void LayoutComplete () {}
GraphicUpdateComplete:图形重建完成事件
1 public virtual void GraphicUpdateComplete () {}
UpdateMaterial:更新UI的材质和纹理
1 2 3 4 5 6 7 8 9 10 11 12 protected virtual void UpdateMaterial (){ if (!IsActive()) return ; canvasRenderer.materialCount = 1 ; canvasRenderer.SetMaterial(materialForRendering, 0 ); canvasRenderer.SetTexture(mainTexture); }
UpdateGeometry:更新 UI 元素的几何体。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 protected virtual void UpdateGeometry (){ if (useLegacyMeshGeneration) { DoLegacyMeshGeneration(); } else { DoMeshGeneration(); } }
DoMeshGeneration:新的生成或更新 UI 元素的网格方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private void DoMeshGeneration (){ if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0 ) OnPopulateMesh(s_VertexHelper); else s_VertexHelper.Clear(); var components = ListPool<Component>.Get(); GetComponents(typeof (IMeshModifier), components); for (var i = 0 ; i < components.Count; i++) ((IMeshModifier)components[i]).ModifyMesh(s_VertexHelper); ListPool<Component>.Release(components); s_VertexHelper.FillMesh(workerMesh); canvasRenderer.SetMesh(workerMesh); }
DoLegacyMeshGeneration:旧的生成或更新 UI 元素的网格方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 private void DoLegacyMeshGeneration () { if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0 ) { #pragma warning disable 618 OnPopulateMesh(workerMesh); #pragma warning restore 618 } else { workerMesh.Clear(); } var components = ListPool<Component>.Get(); GetComponents(typeof (IMeshModifier), components); for (var i = 0 ; i < components.Count; i++) { #pragma warning disable 618 ((IMeshModifier)components[i]).ModifyMesh(workerMesh); #pragma warning restore 618 } ListPool<Component>.Release(components); canvasRenderer.SetMesh(workerMesh); }
OnPopulateMesh:UI元素需要生成顶点时的回调函数。填充顶点缓冲区数据。
1 2 3 4 5 protected virtual void OnPopulateMesh (Mesh m ){ OnPopulateMesh(s_VertexHelper); s_VertexHelper.FillMesh(m); }
OnPopulateMesh:UI元素需要生成顶点时的回调函数。填充顶点缓冲区数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected virtual void OnPopulateMesh (VertexHelper vh ){ var r = GetPixelAdjustedRect(); var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height); Color32 color32 = color; vh.Clear(); vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(0f , 0f )); vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(0f , 1f )); vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(1f , 1f )); vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(1f , 0f )); vh.AddTriangle(0 , 1 , 2 ); vh.AddTriangle(2 , 3 , 0 ); }
GetPixelAdjustedRect:返回最接近图形RectTransform的像素完美矩形。
注意:只有当图形根画布在屏幕空间时才准确。
1 2 3 4 5 6 7 8 9 10 public Rect GetPixelAdjustedRect (){ if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect) return rectTransform.rect; else return RectTransformUtility.PixelAdjustRect(rectTransform, canvas); }
OnDidApplyAnimationProperties:动画属性发生改变时调用
1 2 3 4 protected override void OnDidApplyAnimationProperties (){ SetAllDirty(); }
SetNativeSize:使图形具有其内容的原始大小
1 public virtual void SetNativeSize () {}
Raycast:用于 UI 组件的点击检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public virtual bool Raycast (Vector2 sp, Camera eventCamera ){ if (!isActiveAndEnabled) return false ; var t = transform; var components = ListPool<Component>.Get(); bool ignoreParentGroups = false ; bool continueTraversal = true ; while (t != null ) { t.GetComponents(components); for (var i = 0 ; i < components.Count; i++) { var canvas = components[i] as Canvas; if (canvas != null && canvas.overrideSorting) continueTraversal = false ; var filter = components[i] as ICanvasRaycastFilter; if (filter == null ) continue ; var raycastValid = true ; var group = components[i] as CanvasGroup; if (group != null ) { if (ignoreParentGroups == false && group .ignoreParentGroups) { ignoreParentGroups = true ; raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } else if (!ignoreParentGroups) raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } else { raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); } if (!raycastValid) { ListPool<Component>.Release(components); return false ; } } t = continueTraversal ? t.parent : null ; } ListPool<Component>.Release(components); return true ; }
PixelAdjustPoint:将给定像素点调整为像素完美。
注意:只有当图形根画布在屏幕空间时才准确。
1 2 3 4 5 6 7 8 9 public Vector2 PixelAdjustPoint (Vector2 point ){ if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect) return point; else { return RectTransformUtility.PixelAdjustPoint(point, transform, canvas); } }
CrossFadeColor:使用RGB模式实现颜色渐变效果的方法
1 2 3 4 5 6 7 8 public virtual void CrossFadeColor (Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha ){ CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha, true ); }
CrossFadeColor:将颜色渐变到目标颜色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public virtual void CrossFadeColor (Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha, bool useRGB ){ if (canvasRenderer == null || (!useRGB && !useAlpha)) return ; Color currentColor = canvasRenderer.GetColor(); if (currentColor.Equals(targetColor)) { m_ColorTweenRunner.StopTween(); return ; } ColorTween.ColorTweenMode mode = (useRGB && useAlpha ? ColorTween.ColorTweenMode.All : (useRGB ? ColorTween.ColorTweenMode.RGB : ColorTween.ColorTweenMode.Alpha)); var colorTween = new ColorTween {duration = duration, startColor = canvasRenderer.GetColor(), targetColor = targetColor}; colorTween.AddOnChangedCallback(canvasRenderer.SetColor); colorTween.ignoreTimeScale = ignoreTimeScale; colorTween.tweenMode = mode; m_ColorTweenRunner.StartTween(colorTween); }
CreateColorFromAlpha:根据指定的透明度(alpha
)创建一个带有该透明度的黑色颜色对象
1 2 3 4 5 6 static private Color CreateColorFromAlpha (float alpha ){ var alphaColor = Color.black; alphaColor.a = alpha; return alphaColor; }
CrossFadeAlpha:使用Alpha模式实现颜色渐变效果的方法
1 2 3 4 5 6 7 public virtual void CrossFadeAlpha (float alpha, float duration, bool ignoreTimeScale ){ CrossFadeColor(CreateColorFromAlpha(alpha), duration, ignoreTimeScale, true , false ); }
添加事件监听方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public void RegisterDirtyLayoutCallback (UnityAction action ){ m_OnDirtyLayoutCallback += action; } public void UnregisterDirtyLayoutCallback (UnityAction action ){ m_OnDirtyLayoutCallback -= action; } public void RegisterDirtyVerticesCallback (UnityAction action ){ m_OnDirtyVertsCallback += action; } public void UnregisterDirtyVerticesCallback (UnityAction action ){ m_OnDirtyVertsCallback -= action; } public void RegisterDirtyMaterialCallback (UnityAction action ){ m_OnDirtyMaterialCallback += action; } public void UnregisterDirtyMaterialCallback (UnityAction action ){ m_OnDirtyMaterialCallback -= action; }
Unity编辑器中的方法
OnRebuildRequested:主要处理在编辑模式下当需要重新构建 UI 图形时的行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #if UNITY_EDITOR public virtual void OnRebuildRequested () { var mbs = gameObject.GetComponents<MonoBehaviour>(); foreach (var mb in mbs) { if (mb == null ) continue ; var methodInfo = mb.GetType().GetMethod("OnValidate" , BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (methodInfo != null ) methodInfo.Invoke(mb, null ); } } protected override void Reset () { SetAllDirty(); } #endif
OnValidate:编辑器模式下,脚本的属性在 Inspector 中被更改时自动调用
1 2 3 4 5 6 7 8 #if UNITY_EDITOR protected override void OnValidate () { base .OnValidate(); SetAllDirty(); } #endif