UGUI 右键菜单

好久好久没写博客了呢。。。随便写写

先来张效果图

下面正式开始

using System;
using UnityEngine;

[Serializable]
public struct MenuContentData
{
    static Font _defaultFont;
    public int fontSize;
    public float menuWidth;
    public Font font;
    public Color fontColor;
    public Color fontSuspendColor;
    public Color backgroundColor;
    public Color suspendColor;
    
    static Font defaultFont
    {
        get
        {
            //加载系统默认字体
            return _defaultFont ?? (_defaultFont = Resources.GetBuiltinResource<Font>("Arial.ttf"));
        }
    }

    public static MenuContentData defaultData
    {
        get
        {
            var data = new MenuContentData();
            data.fontSize = 14;
            data.backgroundColor = Color.white;
            data.suspendColor = Color.blue;
            data.menuWidth = 100;
            data.fontColor = Color.black;
            data.fontSuspendColor = Color.white;
            data.font = defaultFont;
            return data;
        }
    }
}

第一步,先写一个数据结构体用来配置菜单的属性,你或许有疑问为嘛不写在菜单类里面,我认为像这些配置信息什么的还是提供一个统一的方法修改比较好,一开始我想到了直接写一个函数,但是写了2个参数我发现参数太多了,干脆就写了个结构体

 

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

public class MenuContent {

    MenuContentData data = MenuContentData.defaultData;
    Transform parent;
    RectTransform menuBackground;
    RectTransform menu;
    RectTransform suspend;

    List<MenuEvent> events = new List<MenuEvent>();
    List<Menu> texts = new List<Menu>();


    public static MenuContent AddMenuEvent(GameObject gameObject)
    {
        return new MenuContent(gameObject);
    }
    
    MenuContent(GameObject gameObject)
    {
        parent = gameObject.transform;
        //该类来自 https://blog.csdn.net/qq_17813937/article/details/72973009
        //如果你打开了网址,你会发现根本没有这个属性~
        //对Click事件的修改见最后
        EventListener.Get(gameObject).onRightClick += e => {
            //如果第一次使用,先初始化
            if (menuBackground == null) Init();
            Show();
        };
    }
    
    public void SetData(MenuContentData data)
    {
        this.data = data;
    }

    public void Show()
    {
        if (events.Count <= 0) return;

        for (int i = 0; i < events.Count; i++)
        {
            if(texts[i] == null)
            {
                //创建菜单项并添加进入和离开事件
                texts[i] = Menu.Create(i,menu,data.font, data.fontSize);
                texts[i].onEnter = SuspendEnter;
                texts[i].onExit = SuspendExit;
            }
            //初始化菜单项单击事件
            if(texts[i].text.text != events[i].name)
            {
                var e = events[i];
                texts[i].text.name = texts[i].text.text = e.name;
                texts[i].button.onClick.RemoveAllListeners();
                texts[i].button.onClick.AddListener(() => {
                    e.action();
                    Hide();
                });
            }
            //初始化菜单项颜色
            texts[i].text.color = data.fontColor;
        }

        //设置高度并显示
        var y = texts[0].text.rectTransform.sizeDelta.y;
        suspend.sizeDelta = new Vector2(data.menuWidth, y);
        menu.sizeDelta = new Vector2(data.menuWidth, events.Count *y);
        menu.localPosition = Input.mousePosition;
        menuBackground.gameObject.SetActive(true);
    }

    public void Hide()
    {
        menuBackground.gameObject.SetActive(false);
    }

    public MenuContent AddMenu(string name, Action action)
    {
        //检查是否添加了相同的菜单
        for (int i = 0; i < events.Count; i++)
        {
            if (events[i].name == name)
            {
                Debug.LogException(new Exception("Menu key duplication"));
                return this;
            }
        }
        events.Add(new MenuEvent(name,action));
        texts.Add(null);
        return this;
    }

    public MenuContent RemoveMenu(string name)
    {
        for (int i = 0; i < events.Count; i++)
        {
            if (events[i].name == name)
            {
                if (texts[i] != null)
                {
                    GameObject.Destroy(texts[i].text.gameObject);
                }
                events.RemoveAt(i);
                texts.RemoveAt(i);
                break;
            }
        }
        return this;
    }

    private void Init()
    {
        //创建全屏单击关闭背景
        var background = new GameObject().AddComponent<RawImage>();
        background.name = "background";
        background.color = Color.clear;
        menuBackground = background.rectTransform;
        menuBackground.SetParent(parent.parent);
        menuBackground.sizeDelta = new Vector2(Screen.width, Screen.height);
        menuBackground.pivot = Vector2.zero;
        menuBackground.position = new Vector3(0, 0, 0);

        //创建菜单背景
        var mb = new GameObject().AddComponent<RawImage>();
        mb.color = data.backgroundColor;
        menu = mb.rectTransform;
        menu.name = "group";
        menu.SetParent(menuBackground);
        menu.anchorMin = Vector2.up;
        menu.anchorMax = Vector2.up;
        menu.pivot = Vector2.up;

        //创建悬浮背景
        var s = new GameObject().AddComponent<RawImage>();
        s.color = data.suspendColor;
        suspend = s.rectTransform;
        suspend.sizeDelta = new Vector2(data.menuWidth, data.fontSize);
        suspend.SetParent(menu);
        suspend.pivot = Vector2.up;
        suspend.anchorMin = Vector2.up;
        suspend.anchorMax = Vector2.up;
        
        //点击全屏背景隐藏菜单
        EventListener.Get(menuBackground.gameObject).onClick = e => {
            Hide();
        };
    }

    void SuspendEnter(Menu k)
    {
        k.text.color = data.fontSuspendColor;
        suspend.anchoredPosition = k.text.rectTransform.anchoredPosition;
        suspend.gameObject.SetActive(true);
    }

    void SuspendExit(Menu k)
    {
        k.text.color = data.fontColor;
        suspend.gameObject.SetActive(false);
    }

    struct MenuEvent
    {
        public string name;
        public Action action;
        public MenuEvent(string name, Action action)
        {
            this.name = name;
            this.action = action;
        }
    }

    class Menu
    {
        public Text text;
        public Button button;

        public Action<Menu> onEnter;
        public Action<Menu> onExit;

        public static Menu Create(int index, Transform parent, Font font, int fontSize)
        {
            return new Menu(index, parent, font, fontSize);
        }

        Menu(int index,Transform parent, Font font, int fontSize)
        {
            //创建菜单项
            var go = new GameObject();
            go.transform.SetParent(parent);
            text = go.AddComponent<Text>();
            button = go.AddComponent<Button>();
            text.color = Color.black;
            text.font = font;
            text.fontSize = fontSize;

            var rt = text.rectTransform;
            rt.pivot = Vector2.up;
            rt.anchorMin = Vector2.up;
            rt.anchorMax = Vector2.up;
            
            var size = go.AddComponent<ContentSizeFitter>();
            size.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
            //刷新高度
            size.SetLayoutVertical();
            //获得高度后设置菜单项高度
            rt.anchoredPosition = new Vector2(0, -index*rt.sizeDelta.y);
            //设置进入和离开事件
            EventListener.Get(go).onEnter = Enter;
            EventListener.Get(go).onExit = Exit;
        }

        void Enter(PointerEventData e)
        {
            onEnter(this);
        }

        void Exit(PointerEventData e)
        {
            onExit(this);
        }
    }
}

相信注释已经写得很清楚了就不在多说了。下面看看怎么用

public class Test : MonoBehaviour
{
    public MenuContentData data;

    private void Awake()
    {
        var menu = MenuContent.AddMenuEvent(gameObject);
        menu.SetData(data);
        menu.AddMenu("66", () => { Debug.Log(666); });
        menu.AddMenu("99", () => { menu.RemoveMenu("99"); });
    }
}

是不是很简单~

 

 

 

 

    void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
    {
        if (gameObject != null) SetFocus(gameObject);
        if (eventData.clickCount == 1)
        {
            if (onClick != null) onClick(eventData);
            switch (eventData.button)
            {
                case PointerEventData.InputButton.Middle:
                    if (onMiddleClick != null) onMiddleClick(eventData);
                    break;
                case PointerEventData.InputButton.Left:
                    if (onLeftClick != null) onLeftClick(eventData);
                    break;
                case PointerEventData.InputButton.Right:
                    if (onRightClick != null) onRightClick(eventData);
                    break;
            }
        }
        else if (eventData.clickCount == 2)
        {
            if (onDoubleClick != null) onDoubleClick(eventData);
            switch (eventData.button)
            {
                case PointerEventData.InputButton.Middle:
                    if (onMiddleDoubleClick != null) onMiddleDoubleClick(eventData);
                    break;
                case PointerEventData.InputButton.Left:
                    if (onLeftDoubleClick != null) onLeftDoubleClick(eventData);
                    break;
                case PointerEventData.InputButton.Right:
                    if (onRightDoubleClick != null) onRightDoubleClick(eventData);
                    break;
            }
        }
    }

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼游戏开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值