diff --git a/Editor/Helper/GUILayoutHelper.cs b/Editor/Helper/GUILayoutHelper.cs index d73c603..cf2b3ad 100644 --- a/Editor/Helper/GUILayoutHelper.cs +++ b/Editor/Helper/GUILayoutHelper.cs @@ -16,6 +16,50 @@ namespace AlicizaX.UI.Extension.Editor GUILayout.EndHorizontal(); } + public static void DrawProperty(SerializedProperty property, GUISkin skin, string content, + Action changeCallBack) + { + GUILayout.BeginHorizontal(EditorStyles.helpBox); + EditorGUILayout.LabelField(new GUIContent(content), skin.FindStyle("Text"), GUILayout.Width(120)); + + // 保存变化前的值 + object oldValue = SerializedPropertyUtility.GetPropertyValue(property); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(property, new GUIContent("")); + + if (EditorGUI.EndChangeCheck()) + { + // 获取变化后的值 + object newValue = SerializedPropertyUtility.GetPropertyValue(property); + changeCallBack?.Invoke(oldValue, newValue); + } + + GUILayout.EndHorizontal(); + } + + public static void DrawProperty(SerializedProperty property, GUISkin skin, string content, + Action changeCallBack, T defaultValue = default(T)) + { + GUILayout.BeginHorizontal(EditorStyles.helpBox); + EditorGUILayout.LabelField(new GUIContent(content), skin.FindStyle("Text"), GUILayout.Width(120)); + + // 保存变化前的值 + T oldValue = SerializedPropertyUtility.GetPropertyValue(property, defaultValue); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(property, new GUIContent("")); + + if (EditorGUI.EndChangeCheck()) + { + // 获取变化后的值 + T newValue = SerializedPropertyUtility.GetPropertyValue(property, defaultValue); + changeCallBack?.Invoke(oldValue, newValue); + } + + GUILayout.EndHorizontal(); + } + public static void DrawProperty(SerializedProperty property, GUISkin skin, string content, string btnName, Action callback) { GUILayout.BeginHorizontal(EditorStyles.helpBox); diff --git a/Editor/Helper/SerializedPropertyUtility.cs b/Editor/Helper/SerializedPropertyUtility.cs new file mode 100644 index 0000000..c1df018 --- /dev/null +++ b/Editor/Helper/SerializedPropertyUtility.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +public static class SerializedPropertyUtility +{ + /// + /// 获取SerializedProperty的值(返回object类型) + /// + public static object GetPropertyValue(SerializedProperty property) + { + if (property == null) return null; + + switch (property.propertyType) + { + case SerializedPropertyType.Integer: + return property.intValue; + case SerializedPropertyType.Boolean: + return property.boolValue; + case SerializedPropertyType.Float: + return property.floatValue; + case SerializedPropertyType.String: + return property.stringValue; + case SerializedPropertyType.Vector2: + return property.vector2Value; + case SerializedPropertyType.Vector3: + return property.vector3Value; + case SerializedPropertyType.Vector4: + return property.vector4Value; + case SerializedPropertyType.Quaternion: + return property.quaternionValue; + case SerializedPropertyType.Color: + return property.colorValue; + case SerializedPropertyType.ObjectReference: + return property.objectReferenceValue; + case SerializedPropertyType.Enum: + return property.enumValueIndex; + case SerializedPropertyType.Vector2Int: + return property.vector2IntValue; + case SerializedPropertyType.Vector3Int: + return property.vector3IntValue; + case SerializedPropertyType.Rect: + return property.rectValue; + case SerializedPropertyType.RectInt: + return property.rectIntValue; + case SerializedPropertyType.Bounds: + return property.boundsValue; + case SerializedPropertyType.BoundsInt: + return property.boundsIntValue; + case SerializedPropertyType.AnimationCurve: + return property.animationCurveValue; + case SerializedPropertyType.Generic: + default: + // 对于不支持的类型或复杂类型,返回null或尝试其他处理 + Debug.LogWarning($"Unsupported property type: {property.propertyType}"); + return null; + } + } + + /// + /// 获取SerializedProperty的值(泛型版本) + /// + public static T GetPropertyValue(SerializedProperty property, T defaultValue = default(T)) + { + try + { + object value = GetPropertyValue(property); + if (value == null) return defaultValue; + + // 如果类型匹配,直接返回 + if (value is T typedValue) + return typedValue; + + // 尝试类型转换 + return (T)Convert.ChangeType(value, typeof(T)); + } + catch (Exception e) + { + Debug.LogWarning($"Failed to get property value as type {typeof(T).Name}: {e.Message}"); + return defaultValue; + } + } + + /// + /// 安全地获取属性值,返回是否成功 + /// + public static bool TryGetPropertyValue(SerializedProperty property, out T value, T defaultValue = default(T)) + { + value = defaultValue; + + try + { + value = GetPropertyValue(property, defaultValue); + return true; + } + catch + { + return false; + } + } +} diff --git a/Editor/Helper/SerializedPropertyUtility.cs.meta b/Editor/Helper/SerializedPropertyUtility.cs.meta new file mode 100644 index 0000000..a7ff8e5 --- /dev/null +++ b/Editor/Helper/SerializedPropertyUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7c7a9c6164c04b319c042aeee04ee262 +timeCreated: 1760409703 \ No newline at end of file diff --git a/Editor/UX/UXButtonEditor.cs b/Editor/UX/UXButtonEditor.cs index 6455cd2..71e022c 100644 --- a/Editor/UX/UXButtonEditor.cs +++ b/Editor/UX/UXButtonEditor.cs @@ -27,8 +27,6 @@ internal class UXButtonEditor : Editor private SerializedProperty m_TransitionData; private SerializedProperty m_ChildTransitions; - private UXGroup group; - private int m_ButtonMode; private SerializedProperty m_SelectionState; private ReorderableList m_ChildTransitionList; @@ -57,9 +55,6 @@ internal class UXButtonEditor : Editor m_ChildTransitions = serializedObject.FindProperty("m_ChildTransitions"); m_SelectionState = serializedObject.FindProperty("m_SelectionState"); - group = (UXGroup)m_UXGroup.objectReferenceValue; - m_ButtonMode = m_Mode.enumValueIndex; - hoverAudioClip = serializedObject.FindProperty("hoverAudioClip"); clickAudioClip = serializedObject.FindProperty("clickAudioClip"); @@ -187,7 +182,22 @@ internal class UXButtonEditor : Editor private void DrawGraphicsTab() { EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying); - EditorGUILayout.PropertyField(m_Mode); + var modeType = (ButtonModeType)EditorGUILayout.EnumPopup("Mode", (ButtonModeType)m_Mode.enumValueIndex); + if (modeType != (ButtonModeType)m_Mode.enumValueIndex) + { + if (modeType == ButtonModeType.Normal) + { + ResetEventProperty(m_OnValueChanged); + m_UXGroup.objectReferenceValue = null; + } + else + { + ResetEventProperty(m_OnClick); + } + + m_Mode.enumValueIndex = (int)modeType; + } + EditorGUI.EndDisabledGroup(); var interactable = GUILayoutHelper.DrawToggle(m_Interactable.boolValue, customSkin, "Interactable"); @@ -196,6 +206,7 @@ internal class UXButtonEditor : Editor mTarget.Interactable = interactable; m_SelectionState.enumValueIndex = interactable ? 0 : 4; } + m_Interactable.boolValue = interactable; GUILayout.Space(1); @@ -244,40 +255,21 @@ internal class UXButtonEditor : Editor private void DrawBasicSettings() { - 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) { - GUILayoutHelper.DrawProperty(m_UXGroup, customSkin, "UXGroup"); - - UXGroup newGroup = (UXGroup)m_UXGroup.objectReferenceValue; - if (newGroup != group) + GUILayoutHelper.DrawProperty(m_UXGroup, customSkin, "UXGroup", (oldValue, newValue) => { UXButton self = target as UXButton; - if (group != null) + if (oldValue != null) { - group.UnregisterButton(self); + oldValue.UnregisterButton(self); } - group = newGroup; - if (newGroup != null) + if (newValue != null) { - newGroup.RegisterButton(self); + newValue.RegisterButton(self); } - } + }); } } diff --git a/Runtime/RecyclerView/Layout/GridLayoutManager.cs b/Runtime/RecyclerView/Layout/GridLayoutManager.cs index de1e654..09f0c68 100644 --- a/Runtime/RecyclerView/Layout/GridLayoutManager.cs +++ b/Runtime/RecyclerView/Layout/GridLayoutManager.cs @@ -12,7 +12,7 @@ namespace AlicizaX.UI.RecyclerView public GridLayoutManager() { - this.unit = unit; + unit = cellCount; } public override Vector2 CalculateContentSize() diff --git a/Runtime/UXComponent/Button/UXButton.cs b/Runtime/UXComponent/Button/UXButton.cs index c3b06c4..2f51090 100644 --- a/Runtime/UXComponent/Button/UXButton.cs +++ b/Runtime/UXComponent/Button/UXButton.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; using AlicizaX.UI.Extension; +using AlicizaX.UI.Extension.Utility; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; @@ -138,7 +139,7 @@ public class UXButton : UIBehaviour, IButton, public void OnPointerDown(PointerEventData eventData) { - if (!CanProcess(eventData)) return; + if (!CanProcess()) return; m_IsDown = true; SetState(SelectionState.Pressed); } @@ -160,7 +161,7 @@ public class UXButton : UIBehaviour, IButton, public void OnPointerEnter(PointerEventData eventData) { - if (!CanProcess(eventData)) return; + if (!CanProcess()) return; m_HasExitedWhileDown = false; if (m_IsDown) return; @@ -203,10 +204,9 @@ public class UXButton : UIBehaviour, IButton, #region Logic - private bool CanProcess(PointerEventData eventData) + private bool CanProcess() { return m_Interactable && - eventData.button == PointerEventData.InputButton.Left && !(m_Mode == ButtonModeType.Toggle && Selected); } @@ -272,7 +272,19 @@ public class UXButton : UIBehaviour, IButton, private void TweenColor(TransitionData data, Color color, bool instant) { - data.targetGraphic.CrossFadeColor(color, instant ? 0f : data.colors.fadeDuration, true, true); + if (Application.isPlaying) + { + data.targetGraphic.CrossFadeColor( + color, + instant ? 0f : data.colors.fadeDuration, + true, + true + ); + } + else + { + data.targetGraphic.canvasRenderer.SetColor(color); + } } private static void SwapSprite(TransitionData data, Sprite sprite) diff --git a/Runtime/UXComponent/Group/UXGroup.cs b/Runtime/UXComponent/Group/UXGroup.cs index deae8ea..c7497f8 100644 --- a/Runtime/UXComponent/Group/UXGroup.cs +++ b/Runtime/UXComponent/Group/UXGroup.cs @@ -11,7 +11,6 @@ public class UXGroup : UIBehaviour [SerializeField] private List m_Buttons = new(); private UXButton _current; - private readonly HashSet _registered = new(); public UnityEvent onSelectedChanged = new(); @@ -29,18 +28,18 @@ public class UXGroup : UIBehaviour protected override void OnDestroy() { - foreach (var btn in _registered) + foreach (var btn in m_Buttons) if (btn) btn.Selected = false; - _registered.Clear(); m_Buttons.Clear(); base.OnDestroy(); } public void RegisterButton(UXButton button) { - if (!button || !_registered.Add(button)) return; - if (!m_Buttons.Contains(button)) m_Buttons.Add(button); + if (!button) return; + if (m_Buttons.Contains(button)) return; + m_Buttons.Add(button); if (button.Selected) { @@ -54,7 +53,7 @@ public class UXGroup : UIBehaviour public void UnregisterButton(UXButton button) { - if (!button || !_registered.Remove(button)) return; + if (!button) return; m_Buttons.Remove(button); if (_current == button) _current = null; diff --git a/Runtime/Utility.meta b/Runtime/Utility.meta new file mode 100644 index 0000000..639970d --- /dev/null +++ b/Runtime/Utility.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2997e0ea45404b2bad0969025eb613a5 +timeCreated: 1760407867 \ No newline at end of file diff --git a/Runtime/Utility/SetPropertyUtility.cs b/Runtime/Utility/SetPropertyUtility.cs new file mode 100644 index 0000000..be40dcd --- /dev/null +++ b/Runtime/Utility/SetPropertyUtility.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace AlicizaX.UI.Extension.Utility +{ + internal static class SetPropertyUtility + { + public static bool SetColor(ref Color currentValue, Color newValue) + { + if (currentValue.r == newValue.r && currentValue.g == newValue.g && currentValue.b == newValue.b && currentValue.a == newValue.a) + return false; + + currentValue = newValue; + return true; + } + + public static bool SetStruct(ref T currentValue, T newValue) where T : struct + { + if (EqualityComparer.Default.Equals(currentValue, newValue)) + return false; + + currentValue = newValue; + return true; + } + + public static bool SetClass(ref T currentValue, T newValue) where T : class + { + if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue))) + return false; + + currentValue = newValue; + return true; + } + } +} diff --git a/Runtime/Utility/SetPropertyUtility.cs.meta b/Runtime/Utility/SetPropertyUtility.cs.meta new file mode 100644 index 0000000..0611d0c --- /dev/null +++ b/Runtime/Utility/SetPropertyUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: baab95df60ce49af96e3b0efcf82ed30 +timeCreated: 1760407873 \ No newline at end of file