GUI.BeginClip裁剪使用

yanghui01發表於2024-11-09

public class EditorClipDemoWnd : EditorWindow
{
    [MenuItem("Demos/EditorClipDemoWnd")]
    static void ShowWindow()
    {
        var window = GetWindow<EditorClipDemoWnd>();
        window.titleContent = new GUIContent("EditorClipDemoWnd");
        window.Show();
    }
    
    private string[] m_ToolbarNames = { "scrollOff.y", "renderOff.y", "clip.y" };
    private int m_ToolbarIndex = 0;
    
    ///裁剪區域
    private Rect m_ViewportRect;
    private float m_ContentHeight;
    ///GUI.BeginClip的scrollOffset引數
    private Vector2 m_ScrollOffset;
    /// GUI.BeginClip的renderOffset引數
    private Vector2 m_RenderOffset;
    /// GUI.BeginClip的resetOffset引數
    public bool m_ResetOffset;
    
    private void OnEnable()
    {
        m_ViewportRect = new Rect(0, 0, 200, 60);
    }
    
    private void OnGUI()
    {
        EditorGUI.DrawRect(m_ViewportRect, Color.gray); //繪製出裁剪區域
        
        GUI.BeginClip(m_ViewportRect, m_ScrollOffset, m_RenderOffset, m_ResetOffset);
        {
            //內容超出視口將被裁減掉
            EditorGUILayout.LabelField("aaaaaaa");
            EditorGUILayout.LabelField("bbbbbbb");
            EditorGUILayout.LabelField("ccccccc");
            EditorGUILayout.LabelField("ddddddd");
            EditorGUILayout.LabelField("fffffff");
        }
        GUI.EndClip();
        
        if (Event.current.type == EventType.Repaint)
        {
            var rect = GUILayoutUtility.GetLastRect();
            m_ContentHeight = rect.yMax;
        }
        
        //捲軸放在裁剪區域右側
        float scrollBarMaxPos = Mathf.Max(0, m_ContentHeight - m_ViewportRect.height); //內容超出的部分即為可滾動距離
        float scrollBarPos = Mathf.Clamp(-m_ScrollOffset.y, 0, scrollBarMaxPos);
        Rect scrollBarRect = new Rect(m_ViewportRect.xMax, m_ViewportRect.y, 13, m_ViewportRect.height);
        scrollBarPos = GUI.VerticalScrollbar(scrollBarRect, scrollBarPos, m_ViewportRect.height, 0,
            Mathf.Max(m_ViewportRect.height, m_ContentHeight));
        m_ScrollOffset.y = -scrollBarPos;

        EditorGUILayout.Space();
        m_ToolbarIndex = GUILayout.Toolbar(m_ToolbarIndex, m_ToolbarNames);
        m_ResetOffset = EditorGUILayout.ToggleLeft("resetOffset", m_ResetOffset);
        if (GUILayout.Button("ResetAll"))
        {
            m_ViewportRect.position = Vector2.zero;
            m_ScrollOffset = Vector2.zero;
            m_RenderOffset = Vector2.zero;
            m_ResetOffset = false;
        }

        if (Event.current.isScrollWheel)
        {
            var delta = Event.current.delta; //向下滾動滾輪, delay.y>0
            if (0 == m_ToolbarIndex)
            {
                m_ScrollOffset.y -= delta.y; //scrollOffset.y<0時ui往上移動
                Debug.Log($"delta:{delta.y}, scrollOffset:{m_ScrollOffset.y}");
            }
            else if (1 == m_ToolbarIndex)
            {
                m_RenderOffset.y -= delta.y; //renderOffset.y<0時ui往下移動
                Debug.Log($"delta:{delta.y}, renderOffset:{m_RenderOffset.y}");
            }
            else if (2 == m_ToolbarIndex)
            {
                m_ViewportRect.y -= delta.y; //viewportRect.y<0時ui往上移動
                Debug.Log($"delta:{delta.y}, viewport:{m_ViewportRect.y}");
            }

            Repaint();
        }
    }
    
}

僅scrollOffset.y變小:裁剪區域不變, y<0 ui內容向上移動

僅renderOffset.y變小:裁剪區域大小不變, y<0 viewport向下移動

僅viewportRect.y變大:裁剪區域大小不變,y>0 viewport向下移動

所以:

GUI.BeginClip(new Rect(0, 0, 66, 17), Vector2.zero, new Vector2(0, -10), false);
GUI.BeginClip(new Rect(0, 10, 66, 17), Vector2.zero, new Vector2(0, 0), false);

可以得到一樣的viewport向下移動10畫素的效果

先viewportRect.y變大,再renderOffset變小,再scrollOffset變小

resetOffset為true時,renderOffset將相對於視窗標題的左上角(而不是裁剪區域的左上角),同時scrollOffset將不起作用

參考:
Unity EditorWindow GUI裁剪 - lunoctis - 部落格園 (cnblogs.com)
UnityEditor ScrollView 簡易分頁 - 知乎 (zhihu.com)

相關文章