• Unity扩展UGUI组件多态按钮MultimodeButton


    Unity扩展UGUI组件多态按钮MultimodeButton

    需求描写

    多态按钮,即按钮每触发一次就会切换一张按钮贴图,并触发一个切换事件。
    这个逻辑并不复杂,有很多方式可以实现。这里记录一下,依托UGUI框架所实现的方式,使用时如同普通Button一样,会比较顺手。

    Button

    首先,因为我装载了VS的反编译工具,可以直接将UGUI的Button组件反编译出源码:

    using System;
    using System.Collections;
    using UnityEngine.Events;
    using UnityEngine.EventSystems;
    using UnityEngine.Serialization;
    
    namespace UnityEngine.UI
    {
        [AddComponentMenu("UI/Button", 30)]
        public class Button : Selectable, IPointerClickHandler, IEventSystemHandler, ISubmitHandler
        {
            [Serializable]
            public class ButtonClickedEvent : UnityEvent
            {
            }
    
            [FormerlySerializedAs("onClick")]
            [SerializeField]
            private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
    
            public ButtonClickedEvent onClick
            {
                get
                {
                    return m_OnClick;
                }
                set
                {
                    m_OnClick = value;
                }
            }
    
            protected Button()
            {
            }
    
            private void Press()
            {
                if (IsActive() && IsInteractable())
                {
                    UISystemProfilerApi.AddMarker("Button.onClick", this);
                    m_OnClick.Invoke();
                }
            }
    
            public virtual void OnPointerClick(PointerEventData eventData)
            {
                if (eventData.button == PointerEventData.InputButton.Left)
                {
                    Press();
                }
            }
    
            public virtual void OnSubmit(BaseEventData eventData)
            {
                Press();
                if (IsActive() && IsInteractable())
                {
                    DoStateTransition(SelectionState.Pressed, instant: false);
                    StartCoroutine(OnFinishSubmit());
                }
            }
    
            private IEnumerator OnFinishSubmit()
            {
                float fadeTime = base.colors.fadeDuration;
                float elapsedTime = 0f;
                while (elapsedTime < fadeTime)
                {
                    elapsedTime += Time.unscaledDeltaTime;
                    yield return null;
                }
    
                DoStateTransition(base.currentSelectionState, instant: false);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    我所要做的就是在原Button组件的基础上做些修改来达到效果。当然并不会修改源码,只是将反编译的代码复制一份到自己创建的脚本中,在根据自己的需求修改。

    Multimode Button

    下面就是经过我修改,达到需求的程序代码:

    using System;
    using System.Collections;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.EventSystems;
    using UnityEngine.Serialization;
    using UnityEngine.UI;
    
    namespace my_code
    {
        [RequireComponent(typeof(Image))]
        public class MultimodeButton : Selectable, IPointerClickHandler, IEventSystemHandler, ISubmitHandler
        {
            ///  所有状态图片 
            public Sprite[] m_stateSprites = new Sprite[2];
    
            ///  当前状态索引 
            public int CurrentIndex { get; private set; }
    
            [Serializable]
            public class MultimodeButtonClickedEvent : UnityEvent<int> { }
    
            [FormerlySerializedAs("onClick"), SerializeField]
            private MultimodeButtonClickedEvent m_OnClick = new MultimodeButtonClickedEvent();
    
            public MultimodeButtonClickedEvent onClick { get { return m_OnClick; } set { m_OnClick = value; } }
    
            protected MultimodeButton()
            {
                CurrentIndex = 0;
            }
    
            protected override void Awake()
            {
                transition = Transition.None;
            }
    
            ///  重置为初始状态 
            public void OnReset()
            {
                CurrentIndex = m_stateSprites.Length;
                Press();
            }
    
            private void Press()
            {
                if (IsActive() && IsInteractable())
                {
                    UISystemProfilerApi.AddMarker("Button.onClick", this);
                    if (++CurrentIndex >= m_stateSprites.Length) CurrentIndex = 0;//确认循环
                    image.sprite = m_stateSprites[CurrentIndex];//image切换状态图片
                    m_OnClick.Invoke(CurrentIndex);
                }
            }
    
            public virtual void OnPointerClick(PointerEventData eventData)
            {
                if (eventData.button == PointerEventData.InputButton.Left)
                {
                    Press();
                }
            }
    
            public virtual void OnSubmit(BaseEventData eventData)
            {
                Press();
                if (IsActive() && IsInteractable())
                {
                    DoStateTransition(SelectionState.Pressed, instant: false);
                    StartCoroutine(OnFinishSubmit());
                }
            }
    
            private IEnumerator OnFinishSubmit()
            {
                float fadeTime = base.colors.fadeDuration;
                float elapsedTime = 0f;
                while (elapsedTime < fadeTime)
                {
                    elapsedTime += Time.unscaledDeltaTime;
                    yield return null;
                }
    
                DoStateTransition(base.currentSelectionState, instant: false);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    两个代码相差不大,其中的逻辑应该很容易理解,这里只把几个比较重要的核心逻辑解释一下:

    • RequireComponent(typeof(Image))多态按钮因为要修改UI的贴图,所以Image是必须的;
    • m_stateSprites:多个状态贴图的存储数组;
    • CurrentIndex:当前状态在数组中的索引;
    • MultimodeButtonClickedEvent:按钮所使用的事件对象类,相比一般的Button,其实就是多了一个状态索引的参数,传入的就是CurrentIndex
    • transition = Transition.None;:个人习惯,通过拖拽到物体上使用时,就不用在手动设置了;
    • OnReset():一个重置函数,可以通过调用这个函数,将按钮重置回CurrentIndex = 0;的初始状态;
    • Press():与一般Button.Press()方法对比,就是多了个贴图循环切换的逻辑。

    项目实际使用效果图

    XX
    1
    2

  • 相关阅读:
    〔004〕Java 基础之数组、方法
    C Primer Plus(6) 中文版 第11章 字符串和字符串函数 11.6 字符串示例:字符串排序
    成都力寰璨泓科技有限公司抖音小店品质保障
    Kafka收发消息核心参数详解
    1123. 最深叶节点的最近公共祖先
    如何解决Blender装配中常见问题,修复角色的绑定问题?
    浅浅的 C编译过程
    动态加载sprite是multiple模式(即该sprite包含了很多小图)里的小图
    googletest简介
    计数的窗口函数应用(2)
  • 原文地址:https://blog.csdn.net/f_957995490/article/details/127446407