類似下面這樣的層級結構,白色區域為ScrollView可見區域,RectMask2D添加在ScrollView上,
可以看到Canvas下的Image1沒被裁剪掉,不在Canvas下的Image2裁剪掉了,

【原因分析】
RectMask2D內部有一個裁剪物件串列,只有在這個串列中的物件才會被裁剪,這邊就是Image1沒被添加到這個串列中造成的,
ugui的實作邏輯就是,如果MaskableGraphic物件和RectMask2D層級間,如果出現了Canvas,那這個物件就不會添加進去,
具體的實作可以查看:MaskableGraphic.UpdateClipParent,在這個函式中確定被哪個RectMask2D裁剪(添加到它的裁剪物件串列中)
【解決思路】
添加一個代理類,這個類物件會被添加到RectMask2D的裁剪物件串列中,然后在收到裁剪呼叫的時候,我們把呼叫轉發到Image1去,
1 [DisallowMultipleComponent] 2 public class ClipProxy : MaskableGraphic 3 { 4 //手動設定轉發給哪幾個MaskableGraphic, 如果不指定將獲取所有子孫上的MaskableGraphic組件 5 [SerializeField] private MaskableGraphic[] _manualMaskables; 6 private List<MaskableGraphic> _maskableList; 7 8 public class ClippableEvent : UnityEvent<Rect, bool> {} 9 10 private ClippableEvent _OnCull = new ClippableEvent(); 11 public ClippableEvent onCull 12 { 13 get { return _OnCull; } 14 set { _OnCull = value; } 15 } 16 17 private ClippableEvent _OnSetClipRect = new ClippableEvent(); 18 public ClippableEvent onSetClipRect 19 { 20 get { return _OnSetClipRect; } 21 set { _OnSetClipRect = value; } 22 } 23 24 #region Empty4Raycast的功能 25 26 protected ClipProxy() 27 { 28 useLegacyMeshGeneration = false; 29 } 30 protected override void OnPopulateMesh(VertexHelper toFill) 31 { 32 toFill.Clear(); 33 } 34 35 #endregion 36 37 38 protected override void Awake() 39 { 40 base.Awake(); 41 42 if (null == _manualMaskables || 0 == _manualMaskables.Length) 43 { 44 _maskableList = new List<MaskableGraphic>(); 45 GetComponentsInChildren(false, _maskableList); 46 } 47 else 48 { 49 _maskableList = new List<MaskableGraphic>(_manualMaskables); 50 } 51 } 52 53 public override void Cull(Rect clipRect, bool validRect) 54 { 55 base.Cull(clipRect, validRect); 56 if (null != _maskableList) 57 { 58 for (var j = 0; j < _maskableList.Count; ++j) 59 { 60 var maskable = _maskableList[j]; 61 if (null != maskable & maskable != this) 62 maskable.Cull(clipRect, validRect); 63 } 64 } 65 } 66 67 public override void SetClipRect(Rect value, bool validRect) 68 { 69 base.SetClipRect(value, validRect); 70 if (null != _maskableList) 71 { 72 for (var j = 0; j < _maskableList.Count; ++j) 73 { 74 var maskable = _maskableList[j]; 75 if (null != maskable && maskable != this) 76 maskable.SetClipRect(value, validRect); 77 } 78 } 79 } 80 81 }
最終效果:

【關于IClippable介面】
void Cull(Rect clipRect, bool validRect)
void SetClipRect(Rect value, bool validRect)
這兩個函式的引數類似,可能容易產生混淆,
Cull用于檢測是否要把自己從渲染中剔除的,比如:可以在這邊判斷是否不在ScrollView的可見區域內,不在時可以從渲染中剔除,一定程度上提高渲染性能,
SetClipRect用于設定自己的裁剪區域,比如裁剪區域變大時,重新調整裁剪區域,或者裁剪區域沒了,關掉裁剪區域,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/390312.html
標籤:其他
上一篇:2021年終總結:人類跌落夢境
