// UXButtonEditor.cs #if UNITY_EDITOR using System; using System.Collections.Generic; using Sirenix.OdinInspector.Editor; using UnityEditor; using UnityEditor.AnimatedValues; using UnityEditor.UI; using UnityEngine; using UnityEngine.UI; [CanEditMultipleObjects] [CustomEditor(typeof(UXButton), true)] public class UXButtonEditor : Editor { private SerializedProperty m_Interactable; private SerializedProperty m_Mode; private SerializedProperty m_OnValueChanged; private SerializedProperty m_OnClick; private SerializedProperty m_UXGroup; private SerializedProperty m_TransitionData; private SerializedProperty m_ChildTransitions; private SerializedProperty m_ButtonUISounds; private bool m_ShowChildTransitions = true; private Dictionary m_ChildTransitionFoldouts = new Dictionary(); private UXGroup group; private int m_ButtonMode; private SerializedProperty m_SelectionState; private UXButton mTarget; private void OnEnable() { mTarget = target as UXButton; m_Interactable = serializedObject.FindProperty("m_Interactable"); m_UXGroup = serializedObject.FindProperty("m_UXGroup"); m_Mode = serializedObject.FindProperty("m_Mode"); m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged"); m_OnClick = serializedObject.FindProperty("m_OnClick"); m_TransitionData = serializedObject.FindProperty("m_TransitionData"); m_ChildTransitions = serializedObject.FindProperty("m_ChildTransitions"); m_ButtonUISounds = serializedObject.FindProperty("m_ButtonUISounds"); m_SelectionState = serializedObject.FindProperty("m_SelectionState"); m_ChildTransitionFoldouts.Clear(); group = (UXGroup)m_UXGroup.objectReferenceValue; m_ButtonMode = m_Mode.enumValueIndex; } private void ResetEventProperty(SerializedProperty property) { SerializedProperty persistentCalls = property.FindPropertyRelative("m_PersistentCalls"); SerializedProperty calls = persistentCalls.FindPropertyRelative("m_Calls"); calls.arraySize = 0; property.serializedObject.ApplyModifiedProperties(); } public override void OnInspectorGUI() { serializedObject.Update(); EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying); EditorGUILayout.PropertyField(m_Mode); EditorGUI.EndDisabledGroup(); EditorGUILayout.PropertyField(m_Interactable); GUILayout.Space(1); DrawSelfTransition(); GUILayout.Space(5); DrawChildTransitions(); EditorGUILayout.PropertyField(m_ButtonUISounds); EditorGUILayout.Space(); if (m_Mode.enumValueIndex != m_ButtonMode) { if (m_ButtonMode == (int)ButtonModeType.Normal) { ResetEventProperty(m_OnValueChanged); m_UXGroup.objectReferenceValue = null; } else { ResetEventProperty((m_OnClick)); } m_ButtonMode = m_Mode.enumValueIndex; } if (m_Mode.enumValueIndex == (int)ButtonModeType.Toggle) { EditorGUILayout.PropertyField(m_UXGroup); UXGroup newGroup = (UXGroup)m_UXGroup.objectReferenceValue; if (newGroup != group) { UXButton self = target as UXButton; if (group != null) { group.UnregisterButton(self); } group = newGroup; if (newGroup != null) { newGroup.RegisterButton(self); } } EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_OnValueChanged); } else { EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_OnClick); } serializedObject.ApplyModifiedProperties(); } private void DrawChildTransitions() { m_ShowChildTransitions = EditorGUILayout.Foldout(m_ShowChildTransitions, "Child Transitions", true); if (!m_ShowChildTransitions) return; EditorGUI.indentLevel++; // 列表控制按钮 EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Add Child Transition", GUILayout.Width(150))) { m_ChildTransitions.arraySize++; serializedObject.ApplyModifiedProperties(); } EditorGUILayout.EndHorizontal(); // 遍历列表元素 for (int i = 0; i < m_ChildTransitions.arraySize; i++) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); // 获取当前元素的SerializedProperty SerializedProperty element = m_ChildTransitions.GetArrayElementAtIndex(i); // 初始化折叠状态 if (!m_ChildTransitionFoldouts.ContainsKey(i)) m_ChildTransitionFoldouts[i] = true; // 折叠标题 string elementTitle = $"Child Transition {i}"; if (element.FindPropertyRelative("targetGraphic").objectReferenceValue != null) elementTitle += $" ({element.FindPropertyRelative("targetGraphic").objectReferenceValue.name})"; m_ChildTransitionFoldouts[i] = EditorGUILayout.Foldout(m_ChildTransitionFoldouts[i], elementTitle, true); if (m_ChildTransitionFoldouts[i]) { // 绘制单个TransitionData DrawTransitionData(element); // 删除按钮 EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); var orginColor = GUI.backgroundColor; GUI.backgroundColor = Color.red; if (GUILayout.Button("Remove", GUILayout.Width(80))) { m_ChildTransitions.DeleteArrayElementAtIndex(i); m_ChildTransitionFoldouts.Remove(i); serializedObject.ApplyModifiedProperties(); break; // 删除后退出当前循环 } GUI.backgroundColor = orginColor; EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); EditorGUILayout.Space(5); } EditorGUI.indentLevel--; } private void DrawTransitionData(SerializedProperty transitionData) { SerializedProperty targetGraphic = transitionData.FindPropertyRelative("targetGraphic"); SerializedProperty transition = transitionData.FindPropertyRelative("transition"); SerializedProperty colorBlock = transitionData.FindPropertyRelative("colors"); SerializedProperty spriteState = transitionData.FindPropertyRelative("spriteState"); SerializedProperty animationTriggers = transitionData.FindPropertyRelative("animationTriggers"); EditorGUI.indentLevel++; // 绘制目标图形 EditorGUILayout.PropertyField(targetGraphic); // 获取当前transition类型 var currentTransition = GetTransition(transition); // 绘制transition类型 EditorGUILayout.PropertyField(transition); // 显示警告信息 var graphic = targetGraphic.objectReferenceValue as Graphic; var animation = graphic.GetComponent(); switch (currentTransition) { case Selectable.Transition.ColorTint: if (graphic == null) EditorGUILayout.HelpBox("需要Graphic组件来使用颜色过渡", MessageType.Warning); break; case Selectable.Transition.SpriteSwap: if (!(graphic is Image)) EditorGUILayout.HelpBox("需要Image组件来使用精灵切换", MessageType.Warning); break; case Selectable.Transition.Animation: if (animation == null) EditorGUILayout.HelpBox("需要Animation || Animator组件来使用动画切换", MessageType.Warning); break; } // 绘制对应类型的属性 switch (currentTransition) { case Selectable.Transition.ColorTint: CheckAndSetColorDefaults(colorBlock, targetGraphic); EditorGUILayout.PropertyField(colorBlock); break; case Selectable.Transition.SpriteSwap: EditorGUILayout.PropertyField(spriteState); break; case Selectable.Transition.Animation: EditorGUILayout.PropertyField(animationTriggers); break; } if ((int)currentTransition != transition.enumValueIndex) { graphic.canvasRenderer.SetColor(graphic.color); graphic.color = graphic.color; } EditorGUI.indentLevel--; } void CheckAndSetColorDefaults(SerializedProperty colorBlock, SerializedProperty targetGraphic) { bool isDirty = false; string[] colorProps = new string[] { "m_NormalColor", "m_HighlightedColor", "m_PressedColor", "m_SelectedColor", "m_DisabledColor" }; foreach (var propName in colorProps) { SerializedProperty prop = colorBlock.FindPropertyRelative(propName); Color color = prop.colorValue; if (color.r == 0 && color.g == 0 && color.b == 0 && color.a == 0) { isDirty = true; if (prop.name == "m_PressedColor") { prop.colorValue = new Color(0.7843137f, 0.7843137f, 0.7843137f, 1.0f); } else if (prop.name == "m_DisabledColor") { prop.colorValue = new Color(0.7843137f, 0.7843137f, 0.7843137f, 0.5f); } else { prop.colorValue = Color.white; } } } SerializedProperty fadeDuration = colorBlock.FindPropertyRelative("m_FadeDuration"); SerializedProperty m_ColorMultiplier = colorBlock.FindPropertyRelative("m_ColorMultiplier"); if (isDirty) { m_ColorMultiplier.floatValue = 1f; fadeDuration.floatValue = 0.1f; } var graphic = targetGraphic.objectReferenceValue as Graphic; if (graphic != null) { if (!EditorApplication.isPlaying) { Color color = colorBlock.FindPropertyRelative("m_NormalColor").colorValue; graphic.canvasRenderer.SetColor(color); } else if (m_SelectionState.enumValueIndex == 0) { Color color = colorBlock.FindPropertyRelative("m_NormalColor").colorValue; graphic.canvasRenderer.SetColor(color); } } } private void DrawSelfTransition() { EditorGUILayout.LabelField("Main Transition", EditorStyles.boldLabel); SerializedProperty targetGraphic = m_TransitionData.FindPropertyRelative("targetGraphic"); var graphic = targetGraphic.objectReferenceValue as Graphic; if (graphic == null) { graphic = (target as UXButton).GetComponent(); targetGraphic.objectReferenceValue = graphic; } EditorGUI.indentLevel++; DrawTransitionData(m_TransitionData); EditorGUI.indentLevel--; EditorGUILayout.Space(); } static Selectable.Transition GetTransition(SerializedProperty transition) { return (Selectable.Transition)transition.enumValueIndex; } } #endif