带有搜索功能的Unity GUI组合框

时间:2016-04-27 04:05:42

标签: unity3d

我需要一个列表,列表很多(枚举列表)。现在列表正在使用弹出窗口(组合框),但正常的组合框并没有真正帮助,因为它内部的项目太多了。当尝试选择远离底部的物品时,这有点令人沮丧。打开时,屏幕上的列表已满。

List Picture

当打开一个组合框并输入一个字母时,它只会跳第一个字母,当我按下第二个字母时,列表将跳转到另一个第一个字母开头。例如,我想选择DIAMOND - >我按D键,它将以D开始进入列表。当我按下I时,它将跳转到以I开头而不是DI的项目。

是否有任何GUI组件可以进行搜索?

2 个答案:

答案 0 :(得分:4)

Unity没有像您这样的搜索组件。

但你可以尝试这样的事情(SearchEnumLabel函数):

using System;
using System.Globalization;
using System.Linq;
using UnityEditor;

public enum States
{
    ABCDEF,
    ACBDEF,
    AdEXG,
    bErDSa
}

[CustomEditor(typeof(ObjectControllerTester))]
[CanEditMultipleObjects]
public class ObjectControllerTesterEditor : Editor
{
    States _selected;

    public override void OnInspectorGUI ()
    {
        _selected = SearchEnumLabel("My search enum", _selected);

        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("[Debug]Current selected: "+_selected);
    }

    private String _searchEnumText = "";
    private bool _isSearchEnumLabelInSearch = false;
    private T SearchEnumLabel<T>(String label, T state) where T : struct, IConvertible
    {
        if (!typeof(T).IsEnum)
        {
            EditorGUILayout.LabelField("T must be an enumerated type");
            return state;
        }
        var states = Enum.GetValues(typeof (T)).Cast<object>().Select(o => o.ToString()).ToArray();
        if (string.IsNullOrEmpty(_searchEnumText) && states.Length > 0) _searchEnumText = state.ToString(CultureInfo.InvariantCulture);

        var text = EditorGUILayout.TextField(label, _searchEnumText);
        if (text != _searchEnumText || _isSearchEnumLabelInSearch)
        {
            _searchEnumText = text;
            var mach = states.Select((v,i)=>new {value = v, index = i}).FirstOrDefault(a => a.value.ToLower().StartsWith(text.ToLower()));
            var targetState = state;
            if (mach != null) targetState = (T) Enum.GetValues(typeof (T)).GetValue(mach.index);
            EditorGUILayout.LabelField("Select closest: "+targetState);
            Repaint();
            state = targetState;
            _isSearchEnumLabelInSearch = !string.Equals(_searchEnumText, targetState.ToString(CultureInfo.InvariantCulture), StringComparison.CurrentCultureIgnoreCase);
        }
        return state;
    }
}

此脚本将显示如下内容:

默认视图

Default vision

输入一些数据后

After input some data

===更新===

具有快速选择按钮的更复杂变体

using System;
using System.Globalization;
using System.Linq;
using UnityEditor;
using UnityEngine;

public enum States
{
    ABCDEF,
    ACBDEF,
    AdEXG,
    bErDSa,
    sEOjsfl,
    SdDiaso,
    POsdjaow,
    PSADJsd,
    Oasdo,
    IOQWEnds
}

[CustomEditor(typeof(ObjectControllerTester))]
[CanEditMultipleObjects]
public class ObjectControllerTesterEditor : Editor
{
    States _selected;

    public override void OnInspectorGUI()
    {
        _selected = SearchEnumLabel("My search enum", _selected);

        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("[Debug]Current selected: " + _selected);
    }

    private String _searchEnumText = "";
    private bool _isSearchEnumLabelInSearch = false;
    private T SearchEnumLabel<T>(String label, T state) where T : struct, IConvertible
    {
        if (!typeof(T).IsEnum)
        {
            EditorGUILayout.LabelField("T must be an enumerated type");
            return state;
        }
        var states = Enum.GetValues(typeof(T)).Cast<object>().Select(o => o.ToString()).ToArray();
        if (string.IsNullOrEmpty(_searchEnumText) && states.Length > 0) _searchEnumText = state.ToString(CultureInfo.InvariantCulture);

        var text = EditorGUILayout.TextField(label, _searchEnumText);
        if (text != _searchEnumText || _isSearchEnumLabelInSearch)
        {
            _searchEnumText = text;
            var mach = states.Select((v, i) => new { value = v, index = i }).Where(a => a.value.ToLower().StartsWith(text.ToLower())).ToList();
            var targetState = state;
            if (mach.Any())
            {
                // many of results
                targetState = (T)Enum.GetValues(typeof(T)).GetValue(mach[0].index);
                EditorGUILayout.LabelField("Select closested: " + targetState);
                Repaint();
                var selected = GUILayout.SelectionGrid(-1, mach.Select(v => v.value).ToArray(), 4);
                if (selected != -1)
                {
                    targetState = (T)Enum.GetValues(typeof(T)).GetValue(mach[selected].index);
                    _searchEnumText = targetState.ToString(CultureInfo.InvariantCulture);
                    _isSearchEnumLabelInSearch = false;
                    GUI.FocusControl("FocusAway");
                    Repaint();
                }
            }
            state = targetState;
            _isSearchEnumLabelInSearch = !string.Equals(_searchEnumText, targetState.ToString(CultureInfo.InvariantCulture), StringComparison.CurrentCultureIgnoreCase);
        }
        return state;
    }
}

点击按钮选择目标枚举 Tap to button to select target enum

答案 1 :(得分:1)

这是我的解决方案,您可以根据需要更换“EnumNBEvent”。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Newborn.Pb.Event;
using System;
using System.Reflection;
using Google.Protobuf.Reflection;
using System.Text.RegularExpressions;


[CustomPropertyDrawer(typeof(EnumNBEvent), false)]
public class FSMEventDrawer : PropertyDrawer {

    struct EnumStringValuePair : IComparable<EnumStringValuePair>
    {
        public string strValue;
        public int intValue;

        public int CompareTo(EnumStringValuePair another)
        {
            if (intValue < another.intValue)
                return -1;
            else if (intValue > another.intValue)
                return 1;
            return 0;
        }
    }

    Dictionary<int, string> filters = new Dictionary<int, string>();
    //string filter = string.Empty;
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        int y = (int)position.position.y;
        if (!filters.ContainsKey(y))
            filters[y] = string.Empty;
        EditorGUI.BeginProperty(position, label, property);
        EditorGUI.LabelField(new Rect(position.x, position.y, 100, 20), property.name);
        filters[y] = EditorGUI.TextField(new Rect(position.x + 100, position.y, 60, 15), filters[y]);
        List<EnumStringValuePair> enumList = GetEnumList(filters[y]);
        List<string> enumStrList = new List<string>(enumList.Count);
        for (int i = 0; i < enumList.Count; ++i)
        {
            enumStrList.Add(enumList[i].strValue);
        }
        int selectedIndex = 0;
        for (int i = 0; i < enumList.Count; ++i)
        {
            if (enumList[i].intValue == property.enumValueIndex)
            {
                selectedIndex = i;
                break;
            }
        }
        selectedIndex = EditorGUI.Popup(new Rect(position.x + 170, position.y, 200, 20), selectedIndex, enumStrList.ToArray());
        if (enumList.Count > selectedIndex)
        {
            property.enumValueIndex = enumList[selectedIndex].intValue;
        }
        EditorGUI.EndProperty();
    }

    private List<EnumStringValuePair> GetEnumList(string filter)
    {
        List<EnumStringValuePair> allList = new List<EnumStringValuePair>();
        Array enumValues = Enum.GetValues(typeof(EnumNBEvent));

        for (int i = 0; i < enumValues.Length; ++i)
        {
            EnumStringValuePair pair = new EnumStringValuePair();
            pair.strValue = enumValues.GetValue(i).ToString();
            pair.intValue = (int)enumValues.GetValue(i);

            allList.Add(pair);
        }

        List<EnumStringValuePair> ret = new List<EnumStringValuePair>();
        Regex regex = new Regex(filter.ToLower());
        for (int i = 0; i < allList.Count; ++i)
        {
            if (regex.IsMatch(allList[i].strValue.ToLower()))
            {
                ret.Add(allList[i]);
            }
        }
        return ret;
    }

}