ugui控件绑定工具


【主要用途】

# 编写gui代码时,会经常用设置Text的文本,设置Image的图片,注册按钮点击,禁用按钮点击这样的操作。

把这些控件绑定到Behaviour上,便于代码访问;减少硬编码去Find控件,硬编码的方式不好的地方在于,界面结构的一旦变化就需要改对应的Find代码,外一忘记就有问题了。

 1 using System.Collections.Generic;
 2 using UnityEngine;
 3 
 4 [System.Serializable]
 5 public class BindObject
 6 {
 7     public UnityEngine.Object value;
 8     public string name;
 9 }
10 
11 [DisallowMultipleComponent]
12 public class BindVar : MonoBehaviour
13 {
14     public BindObject[] bindObjects;
15 
16     private Dictionary<string, UnityEngine.Object> _dict;
17 
18     public UnityEngine.Object GetObject(string name)
19     {
20         if (null == _dict)
21         {
22             _dict = new Dictionary<string, Object>();
23             for (var i = 0; i < bindObjects.Length; ++i)
24             {
25                 var item = bindObjects[i];
26                 _dict.Add(item.name, item.value);
27             }
28         }
29         _dict.TryGetValue(name, out var obj);
30         return obj;
31     }
32 }

# Inspector

  1 #if UNITY_EDITOR
  2 
  3 using System.Text;
  4 using UnityEditor;
  5 using UnityEditorInternal;
  6 using UnityEngine;
  7 
  8 [CustomEditor(typeof(BindVar))]
  9 public class BindVarInspector : UnityEditor.Editor
 10 {
 11     GUIContent _tempGUIContent = new GUIContent();
 12     StringBuilder _sb = new StringBuilder();
 13 
 14     private SerializedObject _serializedObject;
 15     private ReorderableList _bindVarListView;
 16 
 17     void OnEnable()
 18     {
 19         _serializedObject = new SerializedObject(target);
 20         CreateBindVarListView();
 21         EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI;
 22     }
 23 
 24     void OnDisable()
 25     {
 26         EditorApplication.hierarchyWindowItemOnGUI -= HierarchyWindowItemOnGUI;
 27     }
 28 
 29     public override void OnInspectorGUI()
 30     {
 31         EditorGUI.BeginChangeCheck();
 32         _bindVarListView.DoLayoutList();
 33 
 34         if (null != Selection.activeTransform)
 35         {
 36             EditorGUILayout.HelpBox($"{Selection.activeTransform.name}的所有组件, 点击按钮添加Bind条目", MessageType.Info);
 37             if (GUILayout.Button("GameObject"))
 38             {
 39                 var sp_bindVariables = _serializedObject.FindProperty("bindObjects");
 40                 sp_bindVariables.arraySize++;
 41 
 42                 var element = sp_bindVariables.GetArrayElementAtIndex(sp_bindVariables.arraySize - 1);
 43                 element.FindPropertyRelative("value").objectReferenceValue = Selection.activeTransform.gameObject;
 44                 element.FindPropertyRelative("name").stringValue = Selection.activeTransform.name;
 45             }
 46 
 47             var arr = Selection.activeTransform.GetComponents();
 48             for (var i = 0; i < arr.Length; ++i)
 49             {
 50                 if (GUILayout.Button(arr[i].GetType().Name))
 51                 {
 52                     var sp_bindVariables = _serializedObject.FindProperty("bindObjects");
 53                     sp_bindVariables.arraySize++;
 54 
 55                     var element = sp_bindVariables.GetArrayElementAtIndex(sp_bindVariables.arraySize - 1);
 56                     element.FindPropertyRelative("value").objectReferenceValue = arr[i];
 57                     element.FindPropertyRelative("name").stringValue = Selection.activeTransform.name;
 58                 }
 59             }
 60         }
 61 
 62         if (EditorGUI.EndChangeCheck())
 63         {
 64             Debug.Log($"apply: {_serializedObject.ApplyModifiedProperties()}");
 65             Debug.Log($"update: {_serializedObject.UpdateIfRequiredOrScript()}");
 66         }
 67     }
 68 
 69     private void CreateBindVarListView()
 70     {
 71         if (null != _bindVarListView) return;
 72         var sp = _serializedObject.FindProperty("bindObjects");
 73         var listView = new ReorderableList(_serializedObject, sp, true, false, true, true);
 74         _bindVarListView = listView;
 75 
 76         listView.onAddCallback = (sender) =>
 77         {
 78             sender.serializedProperty.arraySize++;
 79             sender.index = sender.serializedProperty.arraySize - 1;
 80 
 81             var element = sender.serializedProperty.GetArrayElementAtIndex(sender.index);
 82             element.FindPropertyRelative("value").objectReferenceValue = null;
 83             element.FindPropertyRelative("name").stringValue = "";
 84         };
 85 
 86         listView.drawElementBackgroundCallback = (rect, index, active, focused) =>
 87         {
 88             if (listView.serializedProperty.arraySize <= 0) return;
 89             
 90             var element = listView.serializedProperty.GetArrayElementAtIndex(index);
 91             var valueProperty = element.FindPropertyRelative("value");
 92             if (null != valueProperty.objectReferenceValue)
 93             {
 94                 if (valueProperty.objectReferenceValue is GameObject)
 95                 {
 96                     if (valueProperty.objectReferenceValue == Selection.activeGameObject)
 97                     {
 98                         if (focused)
 99                         {
100                             EditorGUI.DrawRect(new Rect(rect.x + 2, rect.y, 18, rect.height), Color.cyan);
101                             EditorGUI.DrawRect(new Rect(rect.x + 20, rect.y, 18, rect.height), Color.red);
102                         }
103                         else
104                         {
105                             EditorGUI.DrawRect(new Rect(rect.x + 2, rect.y, 18, rect.height), Color.red);
106                         }
107                     }
108                 }
109                 else
110                 {
111                     var comp = valueProperty.objectReferenceValue as Component;
112                     if (comp.gameObject == Selection.activeGameObject)
113                     {
114                         if (focused)
115                         {
116                             EditorGUI.DrawRect(new Rect(rect.x + 2, rect.y, 18, rect.height), Color.cyan);
117                             EditorGUI.DrawRect(new Rect(rect.x + 20, rect.y, 18, rect.height), Color.red);
118                         }
119                         else
120                         {
121                             EditorGUI.DrawRect(new Rect(rect.x + 2, rect.y, 18, rect.height), Color.red);
122                         }
123                     }
124                 }
125             }
126         };
127 
128         listView.drawElementCallback = (rect, index, active, focused) =>
129         {
130             var element = listView.serializedProperty.GetArrayElementAtIndex(index);
131 
132             var itemRect = rect;
133             itemRect.y += 1.3f; //不贴顶, 上下留
134             itemRect.height = EditorGUIUtility.singleLineHeight; //不设置一些元素会拉伸
135             var halfWidth = rect.width * 0.5f;
136 
137             {
138                 var tempRect = itemRect;
139                 tempRect.width = halfWidth;
140                 EditorGUI.PropertyField(tempRect, element.FindPropertyRelative("value"), GUIContent.none);
141             }
142             {
143                 var tempRect = itemRect;
144                 tempRect.x += halfWidth + 3;
145                 tempRect.width = halfWidth - 3;
146                 EditorGUI.PropertyField(tempRect, element.FindPropertyRelative("name"), GUIContent.none);
147             }
148         };
149 
150         listView.drawHeaderCallback = (rect) => { EditorGUI.LabelField(rect, "Bind Var"); };
151 
152         //listView.DoLayoutList();
153     }
154 
155     void HierarchyWindowItemOnGUI(int instanceID, Rect selectionRect)
156     {
157         var go = (GameObject) EditorUtility.InstanceIDToObject(instanceID);
158 
159         var behaviour = target as BindVar;
160         if (null == behaviour.bindObjects)
161             return;
162 
163         for (var i = 0; i < behaviour.bindObjects.Length; ++i)
164         {
165             var bo = behaviour.bindObjects[i];
166             var bv_value = bo.value;
167             if (null == bv_value)
168                 continue;
169 
170             var tempGo = bv_value as GameObject;
171             if (null == tempGo)
172             {
173                 var comp = bv_value as Component;
174                 if (null != comp)
175                 {
176                     tempGo = comp.gameObject;
177                 }
178                 else
179                 {
180                     Debug.Log($"type??? {bv_value.GetType().Name}, {bv_value.name}");
181                 }
182             }
183 
184             if (go == tempGo)
185             {
186                 var bv_name = bo.name;
187                 if (go.name == bv_name)
188                 {
189                     if (_sb.Length > 0)
190                         _sb.Append(",");
191                     _sb.Append("*");
192                 }
193                 else
194                 {
195                     if (_sb.Length > 0)
196                         _sb.Append(",");
197                     _sb.Append(bv_name);
198                 }
199             }
200         }
201 
202         var str = _sb.ToString();
203         _sb.Clear();
204 
205         _tempGUIContent.text = str;
206         var w = EditorStyles.label.CalcSize(_tempGUIContent).x;
207         var tempRect = selectionRect;
208         tempRect.xMin = selectionRect.xMax - w;
209 
210         var colorBak = GUI.color;
211         GUI.color = Color.yellow;
212         EditorGUI.LabelField(tempRect, str);
213 
214         GUI.color = colorBak;
215     }
216 }
217 
218 #endif

【效果】

# 哪些GameObject被绑定了会在Hierarchy右侧有标记,如果名字同GameObject名就用*显示,如果不同则会显示对应的名字

# Hierarchy中当前所选的GameObject,会在BindVar的列表条目左侧以红色指示