Unity 编辑器下提供了系统级的菜单弹窗,会阻塞消息,卡住渲染,以及不能进行搜索等功能,而它自己有非阻塞版本的弹窗,但不开放给用户使用,比如这个界面:
仿照编辑器源码,修改实现一份:
登录后复制
using System;
using System.Collections;
using System.Globalization;
using UnityEditor;
using UnityEngine;
/// <summary>
/// GenericMenu的Unity风格版本
/// </summary>
public class GenericPopupMenu : PopupWindowContent
{
private class Styles
{
public readonly GUIStyle header = "In BigTitle";
public readonly GUIStyle menuItem = "MenuItem";
public readonly GUIStyle customTextField = "ToolbarSeachTextField";
public readonly GUIStyle customTextFieldCancelButton = "ToolbarSeachCancelButton";
public readonly GUIStyle customTextFieldCancelButtonEmpty = "ToolbarSeachCancelButtonEmpty";
}
private class MenuItem
{
public GUIContent content;
public bool separator;
public bool on;
public GenericMenu.MenuFunction func;
public GenericMenu.MenuFunction2 func2;
public object userData;
public bool enabled = true;
public MenuItem(GUIContent _content, bool _separator, bool _on, GenericMenu.MenuFunction _func)
{
content = _content;
separator = _separator;
on = _on;
func = _func;
}
public MenuItem(GUIContent _content, bool _separator, bool _on, GenericMenu.MenuFunction2 _func, object _userData)
{
content = _content;
separator = _separator;
on = _on;
func2 = _func;
userData = _userData;
}
public MenuItem(GUIContent _content, bool _separator, bool _on, bool _enabled)
{
content = _content;
separator = _separator;
on = _on;
enabled = _enabled;
}
}
private static Styles s_Styles;
private static string s_TextFieldName = "GenericPopupMenuTextField";
private readonly ArrayList m_MenuItems = new ArrayList();
private readonly ArrayList m_MenuFilteredItems = new ArrayList();
private bool m_EnableFiltered = true;
private string m_FilteredText = string.Empty;
private int m_SelectedIndex;
private bool m_FocusText = true;
private double m_FocusTextTime;
private Vector2 m_ScrollPos;
private bool m_IgnoreCase;
public GenericPopupMenu(bool ignoreCase = false)
{
m_IgnoreCase = ignoreCase;
}
public void AddItem(GUIContent content, bool on, GenericMenu.MenuFunction func)
{
m_MenuItems.Add(new MenuItem(content, false, on, func));
}
public void AddItem(GUIContent content, bool on, GenericMenu.MenuFunction2 func, object userData)
{
m_MenuItems.Add(new MenuItem(content, false, on, func, userData));
}
public void AddDisabledItem(GUIContent content)
{
m_MenuItems.Add(new MenuItem(content, false, false, false));
}
public void AddSeparator(string path)
{
m_MenuItems.Add(new MenuItem(new GUIContent(path), true, false, null));
}
public int GetItemCount()
{
return m_MenuItems.Count;
}
public void ShowAsContext()
{
if (Event.current == null)
{
return;
}
DropDown(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 0f, 0f));
}
public void DropDown(Rect position)
{
PopupWindow.Show(position, this);
}
public override void OnOpen()
{
m_MenuFilteredItems.AddRange(m_MenuItems);
}
public override Vector2 GetWindowSize()
{
int maxLen = 0;
for (int i = 0; i < m_MenuItems.Count; i++)
{
string contentText = ((MenuItem) m_MenuItems[i]).content.text;
maxLen = Mathf.Max(maxLen, contentText.Length);
}
float w = 230f;
if (maxLen > 25)
{
w += (maxLen - 25) * 5f;
}
return new Vector2(w, 320f);
}
public override void OnGUI(Rect rect)
{
if (s_Styles == null)
{
s_Styles = new Styles();
}
DrawCustomTextField(rect);
DrawList(rect);
if (Event.current.type == EventType.MouseMove)
{
Event.current.Use();
}
}
private void DrawCustomTextField(Rect rect)
{
if (!m_EnableFiltered)
{
return;
}
Event current = Event.current;
if (current.type == EventType.KeyDown)
{
KeyCode keyCode = current.keyCode;
switch (keyCode)
{
case KeyCode.UpArrow:
ChangeSelectedIndex(-1);
break;
case KeyCode.DownArrow:
ChangeSelectedIndex(1);
break;
case KeyCode.Return:
break;
}
}
string text = m_FilteredText;
Rect rect2 = new Rect(rect.x + 5f, rect.y + 5f, rect.width - 10f - 14f, 16f);
GUI.SetNextControlName(s_TextFieldName);
if (m_FocusText)
{
EditorGUI.FocusTextInControl(s_TextFieldName);
}
else
{
if (m_FocusTextTime > 0 && m_FocusTextTime < EditorApplication.timeSinceStartup)
{
m_FocusText = true;
}
}
string text2 = EditorGUI.TextField(rect2, text, s_Styles.customTextField);
Rect position = rect2;
position.x += rect2.width;
position.width = 14f;
if (GUI.Button(position, GUIContent.none, text2 != string.Empty ? s_Styles.customTextFieldCancelButton : s_Styles.customTextFieldCancelButtonEmpty))
{
text2 = string.Empty;
GUI.FocusControl(null);
m_FocusText = false;
m_FocusTextTime = EditorApplication.timeSinceStartup + 0.3f;
}
if (text != text2)
{
m_FilteredText = text2.ToLower();
m_MenuFilteredItems.Clear();
for (int i = 0; i < m_MenuItems.Count; i++)
{
string contentText = ((MenuItem) m_MenuItems[i]).content.text;
if (m_IgnoreCase)
{
contentText = contentText.ToLower();
}
if (contentText.Contains(m_FilteredText))
{
m_MenuFilteredItems.Add(m_MenuItems[i]);
}
}
}
}
private void DrawList(Rect rect)
{
Rect position = rect;
position.x = 1f;
position.y = 30f;
position.height -= 30f;
position.width -= 2f;
GUILayout.BeginArea(position);
// 绘制标题头,可做分层菜单
//Rect rect3 = GUILayoutUtility.GetRect(10f, 25f);
//string name = String.Empty;
//GUI.Label(rect3, name, s_Styles.header);
m_ScrollPos = GUILayout.BeginScrollView(m_ScrollPos);
for (int i = 0; i < m_MenuFilteredItems.Count; i++)
{
Rect rect2 = GUILayoutUtility.GetRect(16f, 20f, GUILayout.ExpandWidth(true));
DrawListElement(rect2, i, (MenuItem)m_MenuFilteredItems[i]);
}
GUILayout.EndScrollView();
GUILayout.EndArea();
}
private void DrawListElement(Rect rect, int index, MenuItem menuItem)
{
Event current = Event.current;
EventType type = current.type;
switch (type)
{
case EventType.MouseUp:
{
if (Event.current.button == 0 && rect.Contains(current.mousePosition) && menuItem.enabled)
{
current.Use();
if (menuItem.func2 != null)
{
menuItem.func2(menuItem.userData);
}
else if (menuItem.func != null)
{
menuItem.func();
}
editorWindow.Close();
GUIUtility.ExitGUI();
}
}
break;
case EventType.MouseMove:
if (rect.Contains(current.mousePosition))
{
m_SelectedIndex = index;
current.Use();
}
break;
case EventType.Repaint:
{
using (new EditorGUI.DisabledScope(!menuItem.enabled))
{
s_Styles.menuItem.Draw(rect, menuItem.content, index == m_SelectedIndex, menuItem.on, menuItem.on, false);
}
}
break;
}
}
private void ChangeSelectedIndex(int change)
{
int filteredCount = m_MenuFilteredItems.Count;
if (m_SelectedIndex == -1 && change < 0)
{
m_SelectedIndex = filteredCount;
}
int index = filteredCount <= 0 ? 0 : (m_SelectedIndex + change + filteredCount) % filteredCount;
SetSelectedIndex(index);
}
private void SetSelectedIndex(int index)
{
m_SelectedIndex = index;
}
}
效果类似如下:
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删