【UGUI扩展】扩展UGUI Button


源:https://github.com/yangyxd/YxdGameFrame/tree/master/YxdGameFrame/Assets/GameFrame/Frame/UGUI

http://www.cnblogs.com/yangyxd/articles/5308274.html


这个UGUI button 扩展是基于这个项目整理的,斗胆以原创发布。

扩展后的效果:



可以通过这样的形式创建:



详细的完整代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine.Serialization;
#endif


public class UIButtonExtension : UnityEngine.UI.Selectable,
    IPointerClickHandler,
    ISubmitHandler,
    IPointerDownHandler,
    IPointerUpHandler,
    IPointerEnterHandler,
    IPointerExitHandler
{
      /// <summary>
        /// 长按等待时间
        /// </summary>
        public float onLongWaitTime = 1.5f;
        /// <summary>
        /// 不断的产生长按事件
        /// </summary>
        public bool onLongContinue = false;

        [System.Serializable]
        public class ButtonClickedEvent : UnityEvent { }

        [FormerlySerializedAs("onClick")]
        [SerializeField]
        private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
        [FormerlySerializedAs("onLongClick")]
        [SerializeField]
        private ButtonClickedEvent m_OnLongClick = new ButtonClickedEvent();
        [FormerlySerializedAs("onDown")]
        [SerializeField]
        private ButtonClickedEvent m_OnDown = new ButtonClickedEvent();
        [FormerlySerializedAs("onUp")]
        [SerializeField]
        private ButtonClickedEvent m_OnUp = new ButtonClickedEvent();
        [FormerlySerializedAs("onEnter")]
        [SerializeField]
        private ButtonClickedEvent m_OnEnter = new ButtonClickedEvent();
        [FormerlySerializedAs("onExit")]
        [SerializeField]
        private ButtonClickedEvent m_OnExit = new ButtonClickedEvent();

        //private System.Reflection.PropertyInfo pro_isDown;
        //private System.Reflection.PropertyInfo pro_isEnter;

        protected UIButtonExtension() : base() { }

        /// <summary>
        /// 文本值
        /// </summary>
        public string text
        {
            get
            {
                Text v = getText();
                if (v != null)
                    return v.text;
                return null;
            }
            set
            {
                Text v = getText();
                if (v != null)
                    v.text = value;
            }
        }

        private bool isPointerDown = false;
        private bool isPointerInside = false;

        /// <summary>
        /// 是否被按下
        /// </summary>
        public bool isDown
        {
            get
            {
                return isPointerDown;
                /**
                if (pro_isDown == null) {
                    pro_isDown = typeof(Selectable).GetProperty ("isPointerDown", getRBFlag());
                }
                if (pro_isDown == null)
                    return false;
                bool b = (bool) pro_isDown.GetValue (this, null);
                return b;
                */
            }
        }

        /// <summary>
        /// 是否进入
        /// </summary>
        public bool isEnter
        {
            get
            {
                return isPointerInside;
                /**
                if (pro_isEnter == null) {
                    pro_isEnter = typeof(Selectable).GetProperty ("isPointerInside", getRBFlag());
                }
                if (pro_isEnter == null)
                    return false;
                bool b = (bool) pro_isEnter.GetValue (this, null);
                return b;
                */
            }
        }

        /// <summary>
        /// 点击事件
        /// </summary>
        public ButtonClickedEvent onClick
        {
            get { return m_OnClick; }
            set { m_OnClick = value; }
        }

        /// <summary>
        /// 长按事件
        /// </summary>
        public ButtonClickedEvent onLongClick
        {
            get { return m_OnLongClick; }
            set { m_OnLongClick = value; }
        }

        /// <summary>
        /// 按下事件
        /// </summary>
        public ButtonClickedEvent onDown
        {
            get { return m_OnDown; }
            set { m_OnDown = value; }
        }

        /// <summary>
        /// 松开事件
        /// </summary>
        public ButtonClickedEvent onUp
        {
            get { return m_OnUp; }
            set { m_OnUp = value; }
        }

        /// <summary>
        /// 进入事件
        /// </summary>
        public ButtonClickedEvent onEnter
        {
            get { return m_OnEnter; }
            set { m_OnEnter = value; }
        }

        /// <summary>
        /// 离开事件
        /// </summary>
        public ButtonClickedEvent onExit
        {
            get { return m_OnExit; }
            set { m_OnExit = value; }
        }

        private System.Reflection.BindingFlags getRBFlag()
        {
            return System.Reflection.BindingFlags.Static |
                System.Reflection.BindingFlags.NonPublic |
                System.Reflection.BindingFlags.GetProperty |
                System.Reflection.BindingFlags.Instance |
                System.Reflection.BindingFlags.GetField |
                System.Reflection.BindingFlags.ExactBinding;
        }

        private UnityEngine.UI.Text getText()
        {
            Transform f = transform.FindChild("Text");
            Text v = null;
            if (f != null)
            {
                v = f.gameObject.GetComponent<Text>();
            }
            if (v == null && transform.childCount > 0)
            {
                GameObject obj = transform.GetChild(0).gameObject;
                v = obj.GetComponent<Text>();
            }
            return v;
        }

        private void Press()
        {
            if (!IsActive() || !IsInteractable())
                return;
            m_OnClick.Invoke();
        }

        private void Down()
        {
            if (!IsActive() || !IsInteractable())
                return;
            m_OnDown.Invoke();
            StartCoroutine(grow());
        }

        private void Up()
        {
            if (!IsActive() || !IsInteractable() || !isDown)
                return;
            m_OnUp.Invoke();
        }

        private void Enter()
        {
            if (!IsActive())
                return;
            m_OnEnter.Invoke();
        }

        private void Exit()
        {
            if (!IsActive() || !isEnter)
                return;
            m_OnExit.Invoke();
        }

        private void LongClick()
        {
            if (!IsActive() || !isDown)
                return;
            m_OnLongClick.Invoke();
        }

        private float downTime = 0f;
        private IEnumerator grow()
        {
            downTime = Time.time;
            while (isDown)
            {
                if (Time.time - downTime > onLongWaitTime)
                {
                    LongClick();
                    if (onLongContinue)
                        downTime = Time.time;
                    else
                        break;
                }
                else
                    yield return null;
            }
        }

        protected override void OnDisable()
        {
            isPointerDown = false;
            isPointerInside = false;
        }

        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;
            Press();
        }

        public override void OnPointerDown(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;
            isPointerDown = true;
            Down();
            base.OnPointerDown(eventData);
        }

        public override void OnPointerUp(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;
            Up();
            isPointerDown = false;
            base.OnPointerUp(eventData);
        }

        public override void OnPointerEnter(PointerEventData eventData)
        {
            base.OnPointerEnter(eventData);
            isPointerInside = true;
            Enter();
        }

        public override void OnPointerExit(PointerEventData eventData)
        {
            Exit();
            isPointerInside = false;
            base.OnPointerExit(eventData);
        }

        public virtual void OnSubmit(BaseEventData eventData)
        {
            Press();

            // if we get set disabled during the press
            // don't run the coroutine.
            if (!IsActive() || !IsInteractable())
                return;

            DoStateTransition(SelectionState.Pressed, false);
            StartCoroutine(OnFinishSubmit());
        }

        private IEnumerator OnFinishSubmit()
        {
            var fadeTime = colors.fadeDuration;
            var elapsedTime = 0f;

            while (elapsedTime < fadeTime)
            {
                elapsedTime += Time.unscaledDeltaTime;
                yield return null;
            }

            DoStateTransition(currentSelectionState, false);
        }

     public static GameObject CreateUIElementRoot(string name, Vector2 size)
    {
        GameObject go = new GameObject(name);
        RectTransform rect = go.AddComponent<RectTransform>();
        rect.sizeDelta = size;
        return go;
    }
    public static GameObject CreateUIElementRoot(string name, float w, float h)
    {
        return CreateUIElementRoot(name, new Vector2(w, h));
    }

    public static GameObject CreateUIText(string name, string text, GameObject parent)
    {
        GameObject childText = CreateUIObject(name, parent);
        Text v = childText.AddComponent<Text>();
        v.text = text;
        v.alignment = TextAnchor.MiddleCenter;
        SetDefaultTextValues(v);

        RectTransform r = childText.GetComponent<RectTransform>();
        r.anchorMin = Vector2.zero;
        r.anchorMax = Vector2.one;
        r.sizeDelta = Vector2.zero;

        return childText;
    }

    public static GameObject CreateUIObject(string name, GameObject parent)
    {
        GameObject go = new GameObject(name);
        go.AddComponent<RectTransform>();
        SetParentAndAlign(go, parent);
        return go;
    }

    public static void SetDefaultTextValues(Text lbl)
    {
        lbl.color = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f);
    }

    public static void SetParentAndAlign(GameObject child, GameObject parent)
    {
        if (parent == null)
            return;

        child.transform.SetParent(parent.transform, false);
        SetLayerRecursively(child, parent.layer);
    }
    public static void SetLayerRecursively(GameObject go, int layer)
    {
        go.layer = layer;
        Transform t = go.transform;
        for (int i = 0; i < t.childCount; i++)
            SetLayerRecursively(t.GetChild(i).gameObject, layer);
    }

    public static T findRes<T>(string name) where T : Object
    {
        T[] objs = Resources.FindObjectsOfTypeAll<T>();
        if (objs != null && objs.Length > 0)
        {
            foreach (Object obj in objs)
            {
                if (obj.name == name)
                    return obj as T;
            }
        }
        objs = AssetBundle.FindObjectsOfType<T>();
        if (objs != null && objs.Length > 0)
        {
            foreach (Object obj in objs)
            {
                if (obj.name == name)
                    return obj as T;
            }
        }
        return default(T);
    }

    public static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand)
    {
#if UNITY_EDITOR
        GameObject parent = menuCommand.context as GameObject;
        if (parent == null || parent.GetComponentInParent<Canvas>() == null)
        {
            parent = GetOrCreateCanvasGameObject();
        }

        string uniqueName = GameObjectUtility.GetUniqueNameForSibling(parent.transform, element.name);
        element.name = uniqueName;
        Undo.RegisterCreatedObjectUndo(element, "Create " + element.name);
        Undo.SetTransformParent(element.transform, parent.transform, "Parent " + element.name);
        GameObjectUtility.SetParentAndAlign(element, parent);
        if (parent != menuCommand.context) // not a context click, so center in sceneview
            SetPositionVisibleinSceneView(parent.GetComponent<RectTransform>(), element.GetComponent<RectTransform>());

        Selection.activeGameObject = element;
#endif
    }

    public static GameObject GetOrCreateCanvasGameObject()
    {
#if UNITY_EDITOR
        GameObject selectedGo = Selection.activeGameObject;

        // Try to find a gameobject that is the selected GO or one if its parents.
        Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent<Canvas>() : null;
        if (canvas != null && canvas.gameObject.activeInHierarchy)
            return canvas.gameObject;

        // No canvas in selection or its parents? Then use just any canvas..
        canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas;
        if (canvas != null && canvas.gameObject.activeInHierarchy)
            return canvas.gameObject;

        // No canvas in the scene at all? Then create a new one.
        return CreateNewUI();
#else
			return null;
#endif
    }

#if UNITY_EDITOR
    private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform)
    {
        // Find the best scene view
        SceneView sceneView = SceneView.lastActiveSceneView;
        if (sceneView == null && SceneView.sceneViews.Count > 0)
            sceneView = SceneView.sceneViews[0] as SceneView;

        // Couldn't find a SceneView. Don't set position.
        if (sceneView == null || sceneView.camera == null)
            return;

        // Create world space Plane from canvas position.
        Vector2 localPlanePosition;
        Camera camera = sceneView.camera;
        Vector3 position = Vector3.zero;
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition))
        {
            // Adjust for canvas pivot
            localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x;
            localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y;

            localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x);
            localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y);

            // Adjust for anchoring
            position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x;
            position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y;

            Vector3 minLocalPosition;
            minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x;
            minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y;

            Vector3 maxLocalPosition;
            maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x;
            maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y;

            position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x);
            position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y);
        }

        itemTransform.anchoredPosition = position;
        itemTransform.localRotation = Quaternion.identity;
        itemTransform.localScale = Vector3.one;
    }
#endif

    public static GameObject CreateNewUI()
    {
        // Root for the UI
        var root = new GameObject("Canvas");
        root.layer = LayerMask.NameToLayer("UI");
        Canvas canvas = root.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        root.AddComponent<CanvasScaler>();
        root.AddComponent<GraphicRaycaster>();
#if UNITY_EDITOR
        Undo.RegisterCreatedObjectUndo(root, "Create " + root.name);
#endif
        // if there is no event system add one...
        CreateEventSystem(false, null);
        return root;
    }

    public static void CreateEventSystem(bool select, GameObject parent)
    {
#if UNITY_EDITOR
        var esys = Object.FindObjectOfType<EventSystem>();
        if (esys == null)
        {
            var eventSystem = new GameObject("EventSystem");
            GameObjectUtility.SetParentAndAlign(eventSystem, parent);
            esys = eventSystem.AddComponent<EventSystem>();
            eventSystem.AddComponent<StandaloneInputModule>();

            Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name);
        }

        if (select && esys != null)
        {
            Selection.activeGameObject = esys.gameObject;
        }
#endif
    }


#if UNITY_EDITOR
        [MenuItem("GameObject/UI/ButtonEx")]
        static void CreateButtonEx(MenuCommand menuCmd)
        {
            // 创建游戏对象
            float w = 160f;
            float h = 30f;
            GameObject btnRoot = CreateUIElementRoot("ButtonEx", w, h);

            // 创建Text对象
            CreateUIText("Text", "Button", btnRoot);

            // 添加脚本
            btnRoot.AddComponent<CanvasRenderer>();
            Image img = btnRoot.AddComponent<Image>();
            img.color = Color.white;
            img.fillCenter = true;
            img.raycastTarget = true;
            img.sprite = findRes<Sprite>("UISprite");
            if (img.sprite != null)
                img.type = Image.Type.Sliced;

            btnRoot.AddComponent<UIButtonExtension>();
            btnRoot.GetComponent<Selectable>().image = img;

            // 放入到UI Canvas中
            PlaceUIElementRoot(btnRoot, menuCmd);
        }
#endif


    }

   



测试代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;


public class ButtonTest : UIButtonExtension
{
    
    public override void OnPointerClick(PointerEventData eventData)
    {
        //base.OnPointerClick(eventData);
        Debug.Log("OnClick");
    }

    public override void OnPointerDown(PointerEventData eventData)
    {
        //base.OnPointerDown(eventData);
        Debug.Log("OnDown");
    }

    public override void OnPointerEnter(PointerEventData eventData)
    {
        //base.OnPointerEnter(eventData);
        Debug.Log("OnEnter");
    }

    public override void OnPointerExit(PointerEventData eventData)
    {
        //base.OnPointerExit(eventData);
        Debug.Log("OnEixt");
    }

    public override void OnPointerUp(PointerEventData eventData)
    {
        //base.OnPointerUp(eventData);
        Debug.Log("OnUp");
    }
}


效果图:


完!





  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值