MaskableGraphic继承自Graphic,并且继承了IClippable, IMaskable, IMaterialModifier三个接口。它是RawImage、Image和Text的父类。
继承自Graphic的方法:
OnEnable:设置m_ShouldRecalculateStencil(是否需要重新计算模板)为true,调用UpdateClipParent(更新裁剪的父对象),调用SetMaterialDirty(设置材质为脏,Graphic的函数)。若有Mask组件,调用静态函数MaskUtilities.NotifyStencilStateChanged,重新计算Mask。
OnDisable:设置m_ShouldRecalculateStencil为true,依次调用 SetMaterialDirty和UpdateClipParent。在StencilMaterial中移除m_MaskMaterial,并把m_MaskMaterial设为null。若有Mask组件,调用静态函数MaskUtilities.NotifyStencilStateChanged。
OnTransformParentChanged(当父对象改变):设置 m_ShouldRecalculateStencil为true,依次调用UpdateClipParent、SetMaterialDirty。
OnCanvasHierarchyChanged(父对象的Canvas状态改变):设置 m_ShouldRecalculateStencil为true,依次调用UpdateClipParent、SetMaterialDirty。
看一下UpdateClipParent的代码:
private void UpdateClipParent() { var newParent = (maskable && IsActive()) ? MaskUtilities.GetRectMaskForClippable(this) : null; // if the new parent is different OR is now inactive if (m_ParentMask != null && (newParent != m_ParentMask || !newParent.IsActive())) { m_ParentMask.RemoveClippable(this); UpdateCull(false); } // don't re-add it if the newparent is inactive if (newParent != null && newParent.IsActive()) newParent.AddClippable(this); m_ParentMask = newParent; }
调用MaskUtilities.GetRectMaskForClippable找到父对象的RectMask2D组件(RectMask2D组件可以根据RectTransform裁剪子对象,子对象超出父RectTransform范围的部分会被裁剪掉)。
如果newParent不等于m_ParentMask或者newParent是未激活的,就调用RemoveClippable(在RemoveClippable中调用clippable.SetClipRect(new Rect(), false)关闭矩形裁剪,并且把自己从RectMask2D的m_ClipTargets中删除),然后更新剔除。
如果newParent激活,就调用AddClippable(把自己添加到RectMask2D的m_ClipTargets中)。
把newParent赋值给m_ParentMask。
继承自IClippable的方法:
RecalculateClipping(当父对象的IClippable状态改变时调用):调用UpdateClipParent。
Cull:如果validRect为false或者clipRect与rootCanvasRect矩形不重合,调用UpdateCull。UpdateCull中,如果canvasRenderer.cull不等于输入的cull,则canvasRenderer.cull=cull,回调m_OnCullStateChanged,再调用Graphic的OnCullingChanged函数。
SetClipRect:根据传入的validRect值,选择开启或者关闭canvasRenderer的矩形裁剪。
继承自IMaskable的方法:
RecalculateMasking:在StencilMaterial中移除m_MaskMaterial,把m_MaskMaterial设为null,m_ShouldRecalculateStencil设为true,调用SetMaterialDirty函数。
继承自IMaterialModifier的方法:
public virtual Material GetModifiedMaterial(Material baseMaterial) { var toUse = baseMaterial; if (m_ShouldRecalculateStencil) { var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform); m_StencilValue = maskable ? MaskUtilities.GetStencilDepth(transform, rootCanvas) : 0; m_ShouldRecalculateStencil = false; } // if we have a enabled Mask component then it will // generate the mask material. This is an optimisation // it adds some coupling between components though :( Mask maskComponent = GetComponent<Mask>(); if (m_StencilValue > 0 && (maskComponent == null || !maskComponent.IsActive())) { var maskMat = StencilMaterial.Add(toUse, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0); StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = maskMat; toUse = m_MaskMaterial; } return toUse; }
GetModifiedMaterial:如果m_ShouldRecalculateStencil为true,通过MaskUtilities.FindRootSortOverrideCanvas获取rootCanvas,根据maskable,给m_StencilValue赋值为模板深度或者0,m_ShouldRecalculateStencil设为false。
如果 m_StencilValue大于0且Mask组件不存在或者未激活,就把baseMaterial,stencilID,operation等参数添加到StencilMaterial中,并把m_MaskMaterial替换成新的材质。