modify
This commit is contained in:
parent
a2f231014b
commit
35a5416cc4
8
Editor/Res.meta
Normal file
8
Editor/Res.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1c397bc7b14cfb8439960f6f74c953ca
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Editor/Res/d_Button Icon.png
Normal file
BIN
Editor/Res/d_Button Icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 782 B |
117
Editor/Res/d_Button Icon.png.meta
Normal file
117
Editor/Res/d_Button Icon.png.meta
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 337b039db051cab44819dc51e6af1f43
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 13
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
flipGreenChannel: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
vTOnly: 0
|
||||||
|
ignoreMipmapLimit: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: 1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: 0
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: 0
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
flipbookRows: 1
|
||||||
|
flipbookColumns: 1
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
ignorePngGamma: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
swizzle: 50462976
|
||||||
|
cookieLightType: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: Standalone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
customData:
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spriteCustomMetadata:
|
||||||
|
entries: []
|
||||||
|
nameFileIdTable: {}
|
||||||
|
mipmapLimitGroupName:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Editor/Res/d_ToggleGroup Icon.png
Normal file
BIN
Editor/Res/d_ToggleGroup Icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 487 B |
117
Editor/Res/d_ToggleGroup Icon.png.meta
Normal file
117
Editor/Res/d_ToggleGroup Icon.png.meta
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 42b2d97a2cb439b4395c6dca63357d89
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 13
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
flipGreenChannel: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
vTOnly: 0
|
||||||
|
ignoreMipmapLimit: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: 1
|
||||||
|
aniso: 1
|
||||||
|
mipBias: 0
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: 0
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
flipbookRows: 1
|
||||||
|
flipbookColumns: 1
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
ignorePngGamma: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
swizzle: 50462976
|
||||||
|
cookieLightType: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 4
|
||||||
|
buildTarget: Standalone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
customData:
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spriteCustomMetadata:
|
||||||
|
entries: []
|
||||||
|
nameFileIdTable: {}
|
||||||
|
mipmapLimitGroupName:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
3
Editor/UX.meta
Normal file
3
Editor/UX.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f770d49c712145179c9d1e9d6cd6b141
|
||||||
|
timeCreated: 1744275046
|
309
Editor/UX/UXButtonEditor.cs
Normal file
309
Editor/UX/UXButtonEditor.cs
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
// 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<int, bool> m_ChildTransitionFoldouts = new Dictionary<int, bool>();
|
||||||
|
private UXGroup group;
|
||||||
|
private int m_ButtonMode;
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
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_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");
|
||||||
|
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
|
||||||
|
// 绘制目标图形
|
||||||
|
EditorGUILayout.PropertyField(targetGraphic);
|
||||||
|
|
||||||
|
// 获取当前transition类型
|
||||||
|
var currentTransition = GetTransition(transition);
|
||||||
|
|
||||||
|
// 绘制transition类型
|
||||||
|
EditorGUILayout.PropertyField(transition);
|
||||||
|
|
||||||
|
// 显示警告信息
|
||||||
|
var graphic = targetGraphic.objectReferenceValue as Graphic;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制对应类型的属性
|
||||||
|
switch (currentTransition)
|
||||||
|
{
|
||||||
|
case Selectable.Transition.ColorTint:
|
||||||
|
CheckAndSetColorDefaults(colorBlock, targetGraphic);
|
||||||
|
EditorGUILayout.PropertyField(colorBlock);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Selectable.Transition.SpriteSwap:
|
||||||
|
EditorGUILayout.PropertyField(spriteState);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Graphic>();
|
||||||
|
targetGraphic.objectReferenceValue = graphic;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawTransitionData(m_TransitionData);
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Selectable.Transition GetTransition(SerializedProperty transition)
|
||||||
|
{
|
||||||
|
return (Selectable.Transition)transition.enumValueIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
3
Editor/UX/UXButtonEditor.cs.meta
Normal file
3
Editor/UX/UXButtonEditor.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1a6fb65845fb481293f57b30b1bfcb3b
|
||||||
|
timeCreated: 1744275051
|
29
Editor/UX/UXGroupEditor.cs
Normal file
29
Editor/UX/UXGroupEditor.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// using UnityEditor;
|
||||||
|
//
|
||||||
|
// #if UNITY_EDITOR
|
||||||
|
// [CustomEditor(typeof(UXGroup))]
|
||||||
|
// public class UXGroupEditor : Editor
|
||||||
|
// {
|
||||||
|
// private SerializedProperty m_AllowSwitchOff;
|
||||||
|
// private SerializedProperty m_Buttons;
|
||||||
|
// private SerializedProperty m_OnSelectedChanged;
|
||||||
|
//
|
||||||
|
// private void OnEnable()
|
||||||
|
// {
|
||||||
|
// m_AllowSwitchOff = serializedObject.FindProperty("m_AllowSwitchOff");
|
||||||
|
// m_Buttons = serializedObject.FindProperty("m_Buttons");
|
||||||
|
// m_OnSelectedChanged = serializedObject.FindProperty("onSelectedChanged");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public override void OnInspectorGUI()
|
||||||
|
// {
|
||||||
|
// serializedObject.Update();
|
||||||
|
//
|
||||||
|
// EditorGUILayout.PropertyField(m_AllowSwitchOff);
|
||||||
|
// EditorGUILayout.PropertyField(m_Buttons, true);
|
||||||
|
// EditorGUILayout.PropertyField(m_OnSelectedChanged);
|
||||||
|
//
|
||||||
|
// serializedObject.ApplyModifiedProperties();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// #endif
|
3
Editor/UX/UXGroupEditor.cs.meta
Normal file
3
Editor/UX/UXGroupEditor.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d66e1f78170d455c93d71e71ee8f735a
|
||||||
|
timeCreated: 1744275087
|
@ -42,6 +42,11 @@ namespace AlicizaX.UI.RecyclerView
|
|||||||
button.onClick.RemoveAllListeners();
|
button.onClick.RemoveAllListeners();
|
||||||
button.onClick.AddListener(() => action?.Invoke(data));
|
button.onClick.AddListener(() => action?.Invoke(data));
|
||||||
}
|
}
|
||||||
|
else if (TryGetComponent(out UXButton uxButton))
|
||||||
|
{
|
||||||
|
uxButton.onClick.RemoveAllListeners();
|
||||||
|
uxButton.onClick.AddListener(() => action?.Invoke(data));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal void BindChoiceState(bool state)
|
protected internal void BindChoiceState(bool state)
|
||||||
|
3
Runtime/UGUIExtension/UX.meta
Normal file
3
Runtime/UGUIExtension/UX.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d002cbb3729643c7813fdfc55b8beb79
|
||||||
|
timeCreated: 1744274178
|
312
Runtime/UGUIExtension/UX/UXButton.cs
Normal file
312
Runtime/UGUIExtension/UX/UXButton.cs
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AlicizaX;
|
||||||
|
using AlicizaX.UI.Extension;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using AudioType = AlicizaX.Audio.Runtime.AudioType;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public enum ButtonModeType
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
Toggle
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public class TransitionData
|
||||||
|
{
|
||||||
|
public Graphic targetGraphic;
|
||||||
|
public Selectable.Transition transition = Selectable.Transition.ColorTint;
|
||||||
|
public ColorBlock colors;
|
||||||
|
public SpriteState spriteState;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public struct ButtonSoundData
|
||||||
|
{
|
||||||
|
public ButtonSoundType ButtonSoundType;
|
||||||
|
public string ButtonUISoundName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal enum SelectionState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The UI object can be selected.
|
||||||
|
/// </summary>
|
||||||
|
Normal,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The UI object is highlighted.
|
||||||
|
/// </summary>
|
||||||
|
Highlighted,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The UI object is pressed.
|
||||||
|
/// </summary>
|
||||||
|
Pressed,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The UI object is selected
|
||||||
|
/// </summary>
|
||||||
|
Selected,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The UI object cannot be selected.
|
||||||
|
/// </summary>
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DisallowMultipleComponent]
|
||||||
|
[RequireComponent(typeof(Graphic))]
|
||||||
|
public class UXButton : UIBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
|
||||||
|
{
|
||||||
|
[SerializeField] private bool m_Interactable = true;
|
||||||
|
|
||||||
|
|
||||||
|
[SerializeField] private ButtonModeType m_Mode;
|
||||||
|
|
||||||
|
[SerializeField] private UnityEvent m_OnClick = new UnityEvent();
|
||||||
|
|
||||||
|
[SerializeField] private TransitionData m_TransitionData = new TransitionData();
|
||||||
|
|
||||||
|
[SerializeField] private List<TransitionData> m_ChildTransitions = new List<TransitionData>();
|
||||||
|
[SerializeField] private UXGroup m_UXGroup;
|
||||||
|
|
||||||
|
[SerializeField] private List<ButtonSoundCell> m_ButtonUISounds = new List<ButtonSoundCell>();
|
||||||
|
|
||||||
|
private SelectionState m_SelectionState = SelectionState.Normal;
|
||||||
|
private bool m_ExistUI;
|
||||||
|
private bool m_IsDown;
|
||||||
|
private bool m_IsTogSelected;
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsSelected
|
||||||
|
{
|
||||||
|
get { return m_IsTogSelected; }
|
||||||
|
internal set
|
||||||
|
{
|
||||||
|
m_IsTogSelected = value;
|
||||||
|
onValueChanged?.Invoke(m_IsTogSelected);
|
||||||
|
m_SelectionState = m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal;
|
||||||
|
UpdateVisualState(m_SelectionState, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public UnityEvent onClick
|
||||||
|
{
|
||||||
|
get { return m_OnClick; }
|
||||||
|
set { m_OnClick = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[SerializeField] private UnityEvent<bool> m_OnValueChanged = new UnityEvent<bool>();
|
||||||
|
|
||||||
|
public UnityEvent<bool> onValueChanged
|
||||||
|
{
|
||||||
|
get { return m_OnValueChanged; }
|
||||||
|
set { m_OnValueChanged = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Awake()
|
||||||
|
{
|
||||||
|
base.Awake();
|
||||||
|
if (m_Mode == ButtonModeType.Toggle)
|
||||||
|
{
|
||||||
|
onValueChanged?.Invoke(IsSelected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!m_Interactable) return;
|
||||||
|
m_IsDown = true;
|
||||||
|
m_SelectionState = SelectionState.Pressed;
|
||||||
|
UpdateVisualState(m_SelectionState, false);
|
||||||
|
PlayButtonSound(ButtonSoundType.Down);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!m_Interactable) return;
|
||||||
|
m_IsDown = false;
|
||||||
|
|
||||||
|
if (!m_IsTogSelected)
|
||||||
|
{
|
||||||
|
m_SelectionState = m_ExistUI ? SelectionState.Normal : SelectionState.Highlighted;
|
||||||
|
UpdateVisualState(m_SelectionState, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_SelectionState = SelectionState.Selected;
|
||||||
|
UpdateVisualState(m_SelectionState, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_ExistUI)
|
||||||
|
{
|
||||||
|
ProcessClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayButtonSound(ButtonSoundType.Up);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!m_Interactable || CantTouch()) return;
|
||||||
|
m_SelectionState = SelectionState.Highlighted;
|
||||||
|
m_ExistUI = false;
|
||||||
|
UpdateVisualState(m_SelectionState, false);
|
||||||
|
PlayButtonSound(ButtonSoundType.Enter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPointerExitHandler.OnPointerExit(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!m_Interactable) return;
|
||||||
|
if (m_IsDown)
|
||||||
|
{
|
||||||
|
m_ExistUI = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CantTouch())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_SelectionState = SelectionState.Normal;
|
||||||
|
|
||||||
|
UpdateVisualState(m_SelectionState, false);
|
||||||
|
PlayButtonSound(ButtonSoundType.Exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CantTouch()
|
||||||
|
{
|
||||||
|
return m_Mode == ButtonModeType.Toggle && m_IsTogSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessClick()
|
||||||
|
{
|
||||||
|
if (m_Mode == ButtonModeType.Normal)
|
||||||
|
{
|
||||||
|
onClick?.Invoke();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_UXGroup)
|
||||||
|
{
|
||||||
|
m_UXGroup.NotifyButtonClicked(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsSelected = !IsSelected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateVisualState(SelectionState state, bool instant)
|
||||||
|
{
|
||||||
|
ProcessTransitionData(m_TransitionData, state, instant);
|
||||||
|
foreach (var transition in m_ChildTransitions)
|
||||||
|
{
|
||||||
|
ProcessTransitionData(transition, state, instant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ProcessTransitionData(TransitionData transition, SelectionState state, bool instant)
|
||||||
|
{
|
||||||
|
if (transition.targetGraphic == null) return;
|
||||||
|
|
||||||
|
Color tintColor;
|
||||||
|
Sprite transitionSprite;
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case SelectionState.Normal:
|
||||||
|
tintColor = transition.colors.normalColor;
|
||||||
|
transitionSprite = null;
|
||||||
|
break;
|
||||||
|
case SelectionState.Highlighted:
|
||||||
|
tintColor = transition.colors.highlightedColor;
|
||||||
|
transitionSprite = transition.spriteState.highlightedSprite;
|
||||||
|
break;
|
||||||
|
case SelectionState.Pressed:
|
||||||
|
tintColor = transition.colors.pressedColor;
|
||||||
|
transitionSprite = transition.spriteState.pressedSprite;
|
||||||
|
break;
|
||||||
|
case SelectionState.Selected:
|
||||||
|
tintColor = transition.colors.selectedColor;
|
||||||
|
transitionSprite = transition.spriteState.selectedSprite;
|
||||||
|
break;
|
||||||
|
case SelectionState.Disabled:
|
||||||
|
tintColor = transition.colors.disabledColor;
|
||||||
|
transitionSprite = transition.spriteState.disabledSprite;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tintColor = Color.black;
|
||||||
|
transitionSprite = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (transition.transition)
|
||||||
|
{
|
||||||
|
case Selectable.Transition.ColorTint:
|
||||||
|
StartColorTween(transition, tintColor * transition.colors.colorMultiplier, instant);
|
||||||
|
break;
|
||||||
|
case Selectable.Transition.SpriteSwap:
|
||||||
|
DoSpriteSwap(transition, transitionSprite);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void StartColorTween(TransitionData transitionData, Color targetColor, bool instant)
|
||||||
|
{
|
||||||
|
if (Application.isPlaying)
|
||||||
|
{
|
||||||
|
transitionData.targetGraphic.CrossFadeColor(targetColor, instant ? 0f : transitionData.colors.fadeDuration, true, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transitionData.targetGraphic.canvasRenderer.SetColor(targetColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DoSpriteSwap(TransitionData transitionData, Sprite newSprite)
|
||||||
|
{
|
||||||
|
if (transitionData.targetGraphic is Image image)
|
||||||
|
{
|
||||||
|
image.overrideSprite = newSprite;
|
||||||
|
}
|
||||||
|
else if (transitionData.targetGraphic != null)
|
||||||
|
{
|
||||||
|
Log.Error($"Target Graphic must be Image for SpriteSwap. Object: {transitionData.targetGraphic.name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void PlayButtonSound(ButtonSoundType buttonSoundType)
|
||||||
|
{
|
||||||
|
ButtonSoundCell buttonSound = GetButtonSound(buttonSoundType);
|
||||||
|
if (buttonSound == null || string.IsNullOrEmpty(buttonSound.ButtonUISoundName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameApp.Audio.Play(AudioType.UISound, buttonSound.ButtonUISoundName, false, GameApp.Audio.UISoundVolume, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ButtonSoundCell GetButtonSound(ButtonSoundType buttonSoundType)
|
||||||
|
{
|
||||||
|
foreach (var buttonSound in m_ButtonUISounds)
|
||||||
|
{
|
||||||
|
if (buttonSound.ButtonSoundType == buttonSoundType)
|
||||||
|
{
|
||||||
|
return buttonSound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
11
Runtime/UGUIExtension/UX/UXButton.cs.meta
Normal file
11
Runtime/UGUIExtension/UX/UXButton.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d7e92b092d584bb39e5239463f064cbe
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {fileID: 2800000, guid: 337b039db051cab44819dc51e6af1f43, type: 3}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
124
Runtime/UGUIExtension/UX/UXGroup.cs
Normal file
124
Runtime/UGUIExtension/UX/UXGroup.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// UXGroup.cs
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Sirenix.OdinInspector;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
|
[DisallowMultipleComponent]
|
||||||
|
public class UXGroup : UIBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] private bool m_AllowSwitchOff;
|
||||||
|
[ReadOnly] [SerializeField] private List<UXButton> m_Buttons = new List<UXButton>();
|
||||||
|
|
||||||
|
private UXButton currentUXButton = null;
|
||||||
|
|
||||||
|
public UnityEvent<UXButton> onSelectedChanged = new UnityEvent<UXButton>();
|
||||||
|
|
||||||
|
public bool allowSwitchOff
|
||||||
|
{
|
||||||
|
get => m_AllowSwitchOff;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_AllowSwitchOff = value;
|
||||||
|
ValidateGroupState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDestroy()
|
||||||
|
{
|
||||||
|
base.OnDestroy();
|
||||||
|
m_Buttons.Clear();
|
||||||
|
currentUXButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override void Awake()
|
||||||
|
{
|
||||||
|
base.Awake();
|
||||||
|
ValidateGroupState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterButton(UXButton button)
|
||||||
|
{
|
||||||
|
if (!m_Buttons.Contains(button))
|
||||||
|
{
|
||||||
|
m_Buttons.Add(button);
|
||||||
|
if (button.IsSelected)
|
||||||
|
{
|
||||||
|
if (currentUXButton != null && currentUXButton != button)
|
||||||
|
{
|
||||||
|
currentUXButton.IsSelected = false;
|
||||||
|
}
|
||||||
|
currentUXButton = button;
|
||||||
|
}
|
||||||
|
ValidateGroupState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterButton(UXButton button)
|
||||||
|
{
|
||||||
|
if (m_Buttons.Contains(button))
|
||||||
|
{
|
||||||
|
m_Buttons.Remove(button);
|
||||||
|
button.IsSelected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void NotifyButtonClicked(UXButton clickedButton)
|
||||||
|
{
|
||||||
|
if (!clickedButton.IsSelected)
|
||||||
|
{
|
||||||
|
SetSelectedButton(clickedButton);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_AllowSwitchOff)
|
||||||
|
SetSelectedButton(null);
|
||||||
|
else if (currentUXButton != clickedButton)
|
||||||
|
clickedButton.IsSelected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSelectedButton(UXButton targetButton)
|
||||||
|
{
|
||||||
|
UXButton previousSelected = currentUXButton;
|
||||||
|
currentUXButton = null; // 防止递归
|
||||||
|
|
||||||
|
foreach (var button in m_Buttons)
|
||||||
|
{
|
||||||
|
bool shouldSelect = (button == targetButton);
|
||||||
|
if (button.IsSelected != shouldSelect)
|
||||||
|
{
|
||||||
|
button.IsSelected = shouldSelect;
|
||||||
|
}
|
||||||
|
if (shouldSelect) currentUXButton = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousSelected != currentUXButton)
|
||||||
|
{
|
||||||
|
onSelectedChanged.Invoke(currentUXButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateGroupState()
|
||||||
|
{
|
||||||
|
bool anySelected = m_Buttons.Exists(b => b.IsSelected);
|
||||||
|
if (!anySelected && m_Buttons.Count > 0 && !m_AllowSwitchOff)
|
||||||
|
{
|
||||||
|
SetSelectedButton(m_Buttons[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AnyOtherSelected(UXButton exclusion)
|
||||||
|
{
|
||||||
|
foreach (var button in m_Buttons)
|
||||||
|
{
|
||||||
|
if (button != exclusion && button.IsSelected)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
11
Runtime/UGUIExtension/UX/UXGroup.cs.meta
Normal file
11
Runtime/UGUIExtension/UX/UXGroup.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7f0492ee9ffe496c9f028b5f28a10308
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {fileID: 2800000, guid: 42b2d97a2cb439b4395c6dca63357d89, type: 3}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Loading…
Reference in New Issue
Block a user