Unity 编辑器-UGUI拓展Button,一个和原Button一样按钮⭐

拓展Button

需求

想拓展一下UGUI的Button,找了几个帖子,只是能实现功能,但是用起来总有些不尽人意的地方,想办法处理一下

实现

1.创建继承自Button的类

csharp 复制代码
using UnityEngine;
using UnityEngine.UI;

public class CustomButton : Button
{
    [SerializeField] public int audioKey = -1;
    
    protected override void Start()
    {
        base.Start();
        onClick.AddListener(PlaySound);
    }
    
    private void PlaySound()
    {
        if (audioKey != -1)
        {
            // AudioManager.Instance.PlaySound(audioKey);
        }
    }
}

这里只临时做一丢丢功能示例,我们预期的是上面代码中的属性在Inspector中显示出来,然而并没有

2.处理Inspector 显示问题

charp 复制代码
using UnityEditor;
[CustomEditor(typeof(CustomButton))]
public class CustomButtonEditor : UnityEditor.UI.ButtonEditor
{
    public override void OnInspectorGUI()
    {
        var btn = (CustomButton)target;
        btn.audioKey = EditorGUILayout.IntField("Audio Key", btn.audioKey);
        base.OnInspectorGUI();
    }
}

如图,属性已经能正确显示

目前只能通过AddComponent的方式创建,我们预期的是和unity 自带的Button一样的创建方式
注意:editor脚本继承自对应组件的Editor,如上面Button的,继承自 UnityEditor.UI.ButtonEditor,否则Inspector显示可能出现问题

3.处理在prafab中和hierarchy中创建按钮

  • 整理一下Button的使用体验
  • 1. 右键创建
  • 2. 自动挂载Image,用于接收raycast
  • 3. 自动挂载text显示文案
  • 4. 创建节点时,需要区分是否是编辑prefab模式,是否有选中的父节点,确定生成节点的位置
  • 5. 创建节点时,需要区分是否在canvas下等情况,是否需要生成canvas
csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

public class CustomUI : Editor
{
    [MenuItem("GameObject/UI/CustomButton")]
    public static void CreateCustomButton()
    {
        //创建按钮
        var btn = ObjectFactory.CreateGameObject("CustomButton");
        ObjectFactory.AddComponent<RectTransform>(btn);
        var img = ObjectFactory.AddComponent<Image>(btn);
        img.raycastTarget = true;
        img.type = Image.Type.Sliced;
        img.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UISprite.psd");
        ObjectFactory.AddComponent<CustomButton>(btn);
        if (!UnityEditor.SceneManagement.EditorSceneManager.IsPreviewSceneObject(btn))
        {
            //非prefab编辑模式下,需要找父节点canvas
            if (Selection.activeObject != null && Selection.activeObject is GameObject)
            {
                var go = (GameObject)Selection.activeObject;
                if (go.GetComponentInParent<Canvas>(true))
                {
                    btn.transform.SetParent(go.transform);
                }
                else
                {
                    var canvas = CreateCanvas();
                    canvas.transform.SetParent(go.transform);
                    btn.transform.SetParent(canvas.transform);
                }
            }
            else
            {
                var canvas = FindFirstObjectByType<Canvas>();
                if(canvas == null)
                {
                    canvas = CreateCanvas();
                }
                btn.transform.SetParent(canvas.transform);
            }
            
        }
        else
        {
            //prefab编辑模式下,直接添加到选中的物体下
            if (Selection.activeObject != null && Selection.activeObject is GameObject)
            {
                var go = (GameObject)Selection.activeObject;
                btn.transform.SetParent(go.transform);
            }
        }
        btn.GetComponent<RectTransform>().sizeDelta = new Vector2(160, 50);
        btn.transform.localPosition = Vector3.zero;
        //选中按钮节点
        Selection.activeObject = btn;
        //展开到当前节点
        Expend(btn.transform.parent,true);
        //文本
        var txt = ObjectFactory.CreateGameObject("Text");
        ObjectFactory.AddComponent<RectTransform>(txt);
        ObjectFactory.AddComponent<TextMeshProUGUI>(txt);
        txt.transform.SetParent(btn.transform);
        txt.transform.localPosition = Vector3.zero;
        txt.GetComponent<RectTransform>().sizeDelta = new Vector2(160, 50);
        
        //tmp
        var tmp = txt.GetComponent<TextMeshProUGUI>();
        tmp.alignment = TextAlignmentOptions.Center;
        tmp.raycastTarget = false;
        tmp.text = "button";
    }
    /// <summary>
    /// 创建Canvas
    /// </summary>
    /// <returns>canvas</returns>
    private static Canvas CreateCanvas()
    {
        var canvas = ObjectFactory.CreateGameObject("Canvas");
        var c = ObjectFactory.AddComponent<Canvas>(canvas);
        c.renderMode = RenderMode.ScreenSpaceOverlay;
        ObjectFactory.AddComponent<CanvasScaler>(canvas);
        ObjectFactory.AddComponent<GraphicRaycaster>(canvas);
        canvas.layer = LayerMask.NameToLayer("UI");
        return c;
    }
    private static void Expend(Transform transform,bool expand)
    {
        SceneHierarchyUtility.SetExpanded(transform.gameObject,expand);
        if(transform.parent != null)
        {
            Expend(transform.parent,expand);
        }
    }
   
    
}

添加按钮菜单如图所示

4.处理一些细节

创建后如图所示,节点正确创建了,但我们的预期是下面这样,自动选中+展开

自动选中比较简单

charp 复制代码
	Selection.activeObject = btn;

展开找了 网友的方法,很好用

csharp 复制代码
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;


/// <summary>
/// Editor functionalities from internal SceneHierarchyWindow and SceneHierarchy classes. 
/// For that we are using reflection.
/// </summary>
public static class SceneHierarchyUtility
{
    /// <summary>
    /// Check if the target GameObject is expanded (aka unfolded) in the Hierarchy view.
    /// </summary>
    public static bool IsExpanded(GameObject go)
    {
        return GetExpandedGameObjects().Contains(go);
    }

    /// <summary>
    /// Get a list of all GameObjects which are expanded (aka unfolded) in the Hierarchy view.
    /// </summary>
    public static List<GameObject> GetExpandedGameObjects()
    {
        object sceneHierarchy = GetSceneHierarchy();

        MethodInfo methodInfo = sceneHierarchy
            .GetType()
            .GetMethod("GetExpandedGameObjects");

        object result = methodInfo.Invoke(sceneHierarchy, new object[0]);

        return (List<GameObject>)result;
    }

    /// <summary>
    /// Set the target GameObject as expanded (aka unfolded) in the Hierarchy view.
    /// </summary>
    public static void SetExpanded(GameObject go, bool expand)
    {
        object sceneHierarchy = GetSceneHierarchy();

        MethodInfo methodInfo = sceneHierarchy
            .GetType()
            .GetMethod("ExpandTreeViewItem", BindingFlags.NonPublic | BindingFlags.Instance);

        methodInfo.Invoke(sceneHierarchy, new object[] { go.GetInstanceID(), expand });
    }

    /// <summary>
    /// Set the target GameObject and all children as expanded (aka unfolded) in the Hierarchy view.
    /// </summary>
    public static void SetExpandedRecursive(GameObject go, bool expand)
    {
        object sceneHierarchy = GetSceneHierarchy();

        MethodInfo methodInfo = sceneHierarchy
            .GetType()
            .GetMethod("SetExpandedRecursive", BindingFlags.Public | BindingFlags.Instance);

        methodInfo.Invoke(sceneHierarchy, new object[] { go.GetInstanceID(), expand });
    }

    private static object GetSceneHierarchy()
    {
        EditorWindow window = GetHierarchyWindow();

        object sceneHierarchy = typeof(EditorWindow).Assembly
            .GetType("UnityEditor.SceneHierarchyWindow")
            .GetProperty("sceneHierarchy")
            .GetValue(window);

        return sceneHierarchy;
    }

    private static EditorWindow GetHierarchyWindow()
    {
        // For it to open, so that it the current focused window.
        EditorApplication.ExecuteMenuItem("Window/General/Hierarchy");
        return EditorWindow.focusedWindow;
    }
}

完成

相关推荐
一个笔记本4 小时前
godot log | 修改main scene
游戏引擎·godot
nnsix6 小时前
Unity PicoVR开发 实时预览Unity场景 在Pico设备中(串流)
unity·游戏引擎
一只一只12 小时前
Unity之UGUI Button按钮组件详细使用教程
unity·游戏引擎·ugui·button·ugui button
智源研究院官方账号13 小时前
众智FlagOS 1.6发布,以统一架构推动AI硬件、软件技术生态创新发展
数据库·人工智能·算法·架构·编辑器·硬件工程·开源软件
神米米14 小时前
Maya快速安装UE4 布料权重绘制插件PhysX导出apx
游戏引擎·ue4·maya
WarPigs15 小时前
Unity阴影
unity·游戏引擎
一只一只16 小时前
Unity之Invoke
unity·游戏引擎·invoke
技术小甜甜17 小时前
【Godot】【入门】信号系统从 0 到 1(UI/玩法彻底解耦的通用写法)
ui·游戏引擎·godot
咬人喵喵17 小时前
SVG 答题类互动模板汇总(共 16 种/来自 E2 编辑器)
编辑器·svg·e2 编辑器
技术小甜甜19 小时前
【Godot】【入门】节点生命周期怎么用(避免帧循环乱写导致卡顿的范式)
游戏引擎·godot