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的列表条目左侧以红色指示