好久好久没写博客了呢。。。随便写写
先来张效果图
下面正式开始
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;
}
}
}