zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Unity 编辑器开发实战【Create Editor】- RectTransformEditor拓展 Auto Anchors

编辑器开发 实战 Unity create 拓展 Auto Editor
2023-09-27 14:19:52 时间

        通过Editor类中的CreateEditor方法可以实现在不改变原有编辑器布局的情况下进行拓展,下面以RectTransform组件的编辑器为例:             如图所示,我们在不改变RectTransform原有编辑器布局的情况下,添加了一个Auto Anchors功能,该功能方便我们在搭建UI时自动设置锚点。 

        原有的编辑器布局通过CreateEditor方法来创建一个编辑器类,在OnInspectorGUI中调用其OnInspectorGUI方法即可,同时需要在OnSceneGUI中调用其OnSceneGUI方法:

using UnityEngine;
using UnityEditor;

using System.Linq;
using System.Reflection;

namespace SK.Framework
{
    [CustomEditor(typeof(RectTransform)), CanEditMultipleObjects]
    public sealed class RectTransformInspector : Editor
    {
        private Editor instance;
        private MethodInfo onSceneGUI;

        private static readonly object[] emptyArray = new object[0];

        private void OnEnable()
        {
            //获取编辑器类型
            var editorType = Assembly.GetAssembly(typeof(Editor)).GetTypes().FirstOrDefault(m => m.Name == "RectTransformEditor");
            //创建编辑器类实例
            instance = CreateEditor(targets, editorType);
            //通过反射获取OnSceneGUI方法
            onSceneGUI = editorType.GetMethod("OnSceneGUI", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        }

        public override void OnInspectorGUI()
        {
            if (instance)
            {
                instance.OnInspectorGUI();
            }
        }

        private void OnSceneGUI()
        {
            if(instance)
            {
                onSceneGUI.Invoke(instance, emptyArray);
            }
        }
        private void OnDisable()
        {
            if(instance)
            {
                DestroyImmediate(instance);
            }
        }
    }
}

        下面添加拓展功能Auto Anchors,首先我们希望可以多选进行编辑,因此注意需要添加Can Edit Multiple Objects属性,然后在OnInspectorGUI中进行代码添加即可:

public override void OnInspectorGUI()
{
    if (instance)
    {
        instance.OnInspectorGUI();
    }
    GUILayout.Space(20f);

    if (GUILayout.Button("Auto Anchors"))
    {
        //遍历所有选中的RectTransform
        for (int i = 0; i < targets.Length; i++)
        {
            RectTransform tempTarget = targets[i] as RectTransform;
            Undo.RecordObject(tempTarget, "Auto Anchors");
            RectTransform prt = tempTarget.parent as RectTransform;
            Vector2 anchorMin = new Vector2(
                tempTarget.anchorMin.x + tempTarget.offsetMin.x / prt.rect.width,
                tempTarget.anchorMin.y + tempTarget.offsetMin.y / prt.rect.height);
            Vector2 anchorMax = new Vector2(
                tempTarget.anchorMax.x + tempTarget.offsetMax.x / prt.rect.width,
                tempTarget.anchorMax.y + tempTarget.offsetMax.y / prt.rect.height);
            tempTarget.anchorMin = anchorMin;
            tempTarget.anchorMax = anchorMax;
            tempTarget.offsetMin = tempTarget.offsetMax = Vector2.zero;
        }
    }
}

锚点自动设置完成: 

完整代码:

using UnityEngine;
using UnityEditor;

using System.Linq;
using System.Reflection;

namespace SK.Framework
{
    [CustomEditor(typeof(RectTransform)), CanEditMultipleObjects]
    public sealed class RectTransformInspector : Editor
    {
        private MethodInfo onSceneGUI;
        private Editor instance;

        private static readonly object[] emptyArray = new object[0];

        private void OnEnable()
        {
            var editorType = Assembly.GetAssembly(typeof(Editor)).GetTypes().FirstOrDefault(m => m.Name == "RectTransformEditor");
            instance = CreateEditor(targets, editorType);
            onSceneGUI = editorType.GetMethod("OnSceneGUI", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        }

        public override void OnInspectorGUI()
        {
            if (instance)
            {
                instance.OnInspectorGUI();
            }
            GUILayout.Space(20f);

            if(GUILayout.Button("Auto Anchors"))
            {
                for (int i = 0; i < targets.Length; i++)
                {
                    RectTransform tempTarget = targets[i] as RectTransform;
                    Undo.RecordObject(tempTarget, "Auto Anchors");
                    RectTransform prt = tempTarget.parent as RectTransform;
                    Vector2 anchorMin = new Vector2(
                        tempTarget.anchorMin.x + tempTarget.offsetMin.x / prt.rect.width,
                        tempTarget.anchorMin.y + tempTarget.offsetMin.y / prt.rect.height);
                    Vector2 anchorMax = new Vector2(
                        tempTarget.anchorMax.x + tempTarget.offsetMax.x / prt.rect.width,
                        tempTarget.anchorMax.y + tempTarget.offsetMax.y / prt.rect.height);
                    tempTarget.anchorMin = anchorMin;
                    tempTarget.anchorMax = anchorMax;
                    tempTarget.offsetMin = tempTarget.offsetMax = Vector2.zero;
                }
            }
        }

        private void OnSceneGUI()
        {
            if(instance)
            {
                onSceneGUI.Invoke(instance, emptyArray);
            }
        }
        private void OnDisable()
        {
            if(instance)
            {
                DestroyImmediate(instance);
            }
        }
    }
}