2016-04-27 148 views
0

我需要一個列表,它是很多列表(枚舉列表)。現在列表正在使用彈出窗口(組合框),但正常的組合框並不是真的有幫助,因爲它裏面有太多的項目。當嘗試選擇遠離底部的項目時,會感到沮喪。打開時列表在屏幕上已滿。Unity搜索組合框

List Picture

當開擴一個組合框,鍵入一個字母就跳到第一個字母,當我按下第二個字母列表將被跳轉到另一個第一個字母開始。例如,我想選擇DIAMOND - >我按D鍵,它會以D開頭進入列表。當我按I時,它將跳轉到以I開始而不是DI開始的項目。

是否有GUI的任何組件來搜索?

回答

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

=== UPDATE ===快速選擇按鈕

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

+0

哇,我也需要這個,謝謝 – Catwood

+0

嗨@Randomyr,謝謝你的回答。我只是在打開一個新窗口時想到關於枚舉的列表。所以它就像一個按鈕旁邊的按鈕,我們可以點擊並打開窗口。所以所有枚舉列表都會在那裏,我們可以過濾並選擇我們想要的枚舉。那可能嗎? – Apin

+0

@Apin,我已經更新了答案 - 你的意思是這種情況嗎? –

0

這裏是我的解決方案,你可以隨意替換'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; 
} 

}