UXButton UXGroup优化
This commit is contained in:
parent
06aed57569
commit
39630c4f78
Binary file not shown.
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 864 B |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 864 B |
Binary file not shown.
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 884 B |
BIN
Editor/Res/TMP - Text Component Icon.psd
Normal file
BIN
Editor/Res/TMP - Text Component Icon.psd
Normal file
Binary file not shown.
117
Editor/Res/TMP - Text Component Icon.psd.meta
Normal file
117
Editor/Res/TMP - Text Component Icon.psd.meta
Normal file
@ -0,0 +1,117 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4398d454b1a861499ef73d23bc7a032
|
||||
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: 0
|
||||
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:
|
@ -211,7 +211,7 @@ MonoBehaviour:
|
||||
m_ImagePosition: 0
|
||||
m_ContentOffset: {x: 15, y: 1}
|
||||
m_FixedWidth: 24
|
||||
m_FixedHeight: 15
|
||||
m_FixedHeight: 24
|
||||
m_StretchWidth: 1
|
||||
m_StretchHeight: 0
|
||||
m_label:
|
||||
|
@ -9,7 +9,7 @@ using UnityEngine.UI;
|
||||
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(UXButton), true)]
|
||||
public class UXButtonEditor : Editor
|
||||
internal class UXButtonEditor : Editor
|
||||
{
|
||||
private enum TabType
|
||||
{
|
||||
|
@ -1,29 +0,0 @@
|
||||
// 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
|
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d66e1f78170d455c93d71e71ee8f735a
|
||||
timeCreated: 1744275087
|
@ -5,7 +5,7 @@ MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
icon: {fileID: 2800000, guid: c4398d454b1a861499ef73d23bc7a032, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
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;
|
||||
|
||||
@ -16,7 +16,6 @@ public enum ButtonModeType
|
||||
Toggle
|
||||
}
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class TransitionData
|
||||
{
|
||||
@ -24,102 +23,130 @@ public class TransitionData
|
||||
public Selectable.Transition transition = Selectable.Transition.ColorTint;
|
||||
public ColorBlock colors;
|
||||
public SpriteState spriteState;
|
||||
public AnimationTriggers animationTriggers = new AnimationTriggers();
|
||||
public AnimationTriggers animationTriggers = new();
|
||||
}
|
||||
|
||||
|
||||
internal enum SelectionState
|
||||
{
|
||||
Normal,
|
||||
|
||||
Highlighted,
|
||||
|
||||
Pressed,
|
||||
|
||||
Selected,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
[ExecuteInEditMode]
|
||||
[DisallowMultipleComponent]
|
||||
public class UXButton : UIBehaviour, IButton,
|
||||
IPointerDownHandler,
|
||||
IPointerUpHandler,
|
||||
IPointerEnterHandler,
|
||||
IPointerExitHandler,
|
||||
IPointerClickHandler
|
||||
IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler,
|
||||
IPointerExitHandler, IPointerClickHandler, ISubmitHandler
|
||||
{
|
||||
#region Serialized Fields
|
||||
|
||||
[SerializeField] private bool m_Interactable = true;
|
||||
|
||||
[SerializeField] private ButtonModeType m_Mode;
|
||||
|
||||
[SerializeField] private Button.ButtonClickedEvent m_OnClick = new Button.ButtonClickedEvent();
|
||||
|
||||
[SerializeField] private TransitionData m_TransitionData = new TransitionData();
|
||||
|
||||
[SerializeField] private List<TransitionData> m_ChildTransitions = new List<TransitionData>();
|
||||
[SerializeField] private Button.ButtonClickedEvent m_OnClick = new();
|
||||
[SerializeField] private TransitionData m_TransitionData = new();
|
||||
[SerializeField] private List<TransitionData> m_ChildTransitions = new();
|
||||
[SerializeField] private UXGroup m_UXGroup;
|
||||
|
||||
[SerializeField] private AudioClip hoverAudioClip;
|
||||
[SerializeField] private AudioClip clickAudioClip;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Variables
|
||||
|
||||
[SerializeField] private SelectionState m_SelectionState = SelectionState.Normal;
|
||||
private bool m_DownAndExistUI;
|
||||
private bool m_IsDown;
|
||||
private bool m_IsTogSelected;
|
||||
|
||||
private Animator _animator;
|
||||
private WaitForSeconds _waitTimeFadeDuration;
|
||||
private Coroutine _resetRoutine;
|
||||
private bool _boardEvent;
|
||||
|
||||
private readonly Dictionary<string, int> _animTriggerIDs = new();
|
||||
private readonly Dictionary<string, int> _animResetTriggerIDs = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
internal Animator animator
|
||||
{
|
||||
get
|
||||
{
|
||||
_animator = _animator ?? GetComponent<Animator>();
|
||||
if (!_animator)
|
||||
_animator = GetComponent<Animator>();
|
||||
return _animator;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get { return m_IsTogSelected; }
|
||||
get => m_IsTogSelected;
|
||||
internal set
|
||||
{
|
||||
if (m_IsTogSelected == value) return;
|
||||
m_IsTogSelected = value;
|
||||
onValueChanged?.Invoke(m_IsTogSelected);
|
||||
m_SelectionState = m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal;
|
||||
m_SelectionState = value ? SelectionState.Selected : SelectionState.Normal;
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
}
|
||||
}
|
||||
|
||||
public Button.ButtonClickedEvent onClick
|
||||
{
|
||||
get { return m_OnClick; }
|
||||
set { m_OnClick = value; }
|
||||
get => m_OnClick;
|
||||
set => m_OnClick = value;
|
||||
}
|
||||
|
||||
[SerializeField] private UnityEvent<bool> m_OnValueChanged = new UnityEvent<bool>();
|
||||
[SerializeField] private UnityEvent<bool> m_OnValueChanged = new();
|
||||
|
||||
public UnityEvent<bool> onValueChanged
|
||||
{
|
||||
get { return m_OnValueChanged; }
|
||||
set { m_OnValueChanged = value; }
|
||||
get => m_OnValueChanged;
|
||||
set => m_OnValueChanged = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Lifecycle
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
if (m_Mode == ButtonModeType.Toggle)
|
||||
{
|
||||
onValueChanged?.Invoke(IsSelected);
|
||||
}
|
||||
_waitTimeFadeDuration = new WaitForSeconds(
|
||||
Mathf.Max(0.01f, m_TransitionData.colors.fadeDuration));
|
||||
|
||||
var triggers = m_TransitionData.animationTriggers;
|
||||
AddTriggerID(triggers.normalTrigger);
|
||||
AddTriggerID(triggers.highlightedTrigger);
|
||||
AddTriggerID(triggers.pressedTrigger);
|
||||
AddTriggerID(triggers.selectedTrigger);
|
||||
AddTriggerID(triggers.disabledTrigger);
|
||||
|
||||
UpdateVisualState(m_SelectionState, true);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
if (_resetRoutine != null)
|
||||
{
|
||||
StopCoroutine(_resetRoutine);
|
||||
_resetRoutine = null;
|
||||
}
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
if (!m_Interactable) return;
|
||||
if (eventData.button != PointerEventData.InputButton.Left) return;
|
||||
if (!ShouldProcessEvent(eventData)) return;
|
||||
|
||||
m_IsDown = true;
|
||||
m_SelectionState = SelectionState.Pressed;
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
@ -127,29 +154,30 @@ public class UXButton : UIBehaviour, IButton,
|
||||
|
||||
void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
|
||||
{
|
||||
if (!m_Interactable) return;
|
||||
if (!m_Interactable || eventData.button != PointerEventData.InputButton.Left)
|
||||
return;
|
||||
|
||||
m_IsDown = false;
|
||||
|
||||
if (!m_IsTogSelected)
|
||||
if (m_IsTogSelected)
|
||||
{
|
||||
m_SelectionState = m_DownAndExistUI ? SelectionState.Normal : SelectionState.Highlighted;
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
m_SelectionState = SelectionState.Selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SelectionState = SelectionState.Selected;
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
m_SelectionState = m_DownAndExistUI ? SelectionState.Normal : SelectionState.Highlighted;
|
||||
}
|
||||
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
}
|
||||
|
||||
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (!m_Interactable || CantTouch()) return;
|
||||
if (!ShouldProcessEvent(eventData)) return;
|
||||
|
||||
m_SelectionState = SelectionState.Highlighted;
|
||||
m_DownAndExistUI = false;
|
||||
if (m_IsDown) return;
|
||||
|
||||
m_SelectionState = SelectionState.Highlighted;
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
PlayButtonSound(hoverAudioClip);
|
||||
}
|
||||
@ -163,45 +191,72 @@ public class UXButton : UIBehaviour, IButton,
|
||||
return;
|
||||
}
|
||||
|
||||
if (CantTouch())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SelectionState = SelectionState.Normal;
|
||||
|
||||
m_SelectionState = IsSelected ? SelectionState.Selected : SelectionState.Normal;
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
}
|
||||
|
||||
private bool CantTouch()
|
||||
void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
return m_Mode == ButtonModeType.Toggle && m_IsTogSelected;
|
||||
if (eventData.button != PointerEventData.InputButton.Left || !m_Interactable)
|
||||
return;
|
||||
|
||||
PlayButtonSound(clickAudioClip);
|
||||
ProcessClick();
|
||||
}
|
||||
|
||||
void ISubmitHandler.OnSubmit(BaseEventData eventData)
|
||||
{
|
||||
UpdateVisualState(SelectionState.Pressed, false);
|
||||
ProcessClick();
|
||||
|
||||
if (_resetRoutine != null)
|
||||
StopCoroutine(OnFinishSubmit());
|
||||
|
||||
_resetRoutine = StartCoroutine(OnFinishSubmit());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void SetSelect(bool state, bool boardEvent = false)
|
||||
{
|
||||
if (m_Mode != ButtonModeType.Toggle) return;
|
||||
m_IsTogSelected = state;
|
||||
if (boardEvent) onValueChanged?.Invoke(m_IsTogSelected);
|
||||
m_SelectionState = m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal;
|
||||
UpdateVisualState(m_SelectionState, false);
|
||||
_boardEvent = boardEvent;
|
||||
IsSelected = state;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private bool ShouldProcessEvent(PointerEventData eventData)
|
||||
{
|
||||
return m_Interactable &&
|
||||
eventData.button == PointerEventData.InputButton.Left &&
|
||||
!(m_Mode == ButtonModeType.Toggle && IsSelected);
|
||||
}
|
||||
|
||||
private void ProcessClick()
|
||||
{
|
||||
if (!_boardEvent)
|
||||
{
|
||||
_boardEvent = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_boardEvent = true;
|
||||
if (m_Mode == ButtonModeType.Normal)
|
||||
{
|
||||
UISystemProfilerApi.AddMarker("Button.onClick", this);
|
||||
onClick?.Invoke();
|
||||
m_OnClick?.Invoke();
|
||||
}
|
||||
else if (m_UXGroup)
|
||||
{
|
||||
m_UXGroup.NotifyButtonClicked(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_UXGroup)
|
||||
{
|
||||
m_UXGroup.NotifyButtonClicked(this);
|
||||
return;
|
||||
}
|
||||
|
||||
IsSelected = !IsSelected;
|
||||
}
|
||||
}
|
||||
@ -215,7 +270,6 @@ public class UXButton : UIBehaviour, IButton,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ProcessTransitionData(TransitionData transition, SelectionState state, bool instant)
|
||||
{
|
||||
if (transition.targetGraphic == null) return;
|
||||
@ -223,11 +277,12 @@ public class UXButton : UIBehaviour, IButton,
|
||||
Color tintColor;
|
||||
Sprite transitionSprite;
|
||||
string triggerName;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case SelectionState.Normal:
|
||||
tintColor = transition.colors.normalColor;
|
||||
transitionSprite = null;
|
||||
transitionSprite = transition.spriteState.highlightedSprite;
|
||||
triggerName = transition.animationTriggers.normalTrigger;
|
||||
break;
|
||||
case SelectionState.Highlighted:
|
||||
@ -251,10 +306,7 @@ public class UXButton : UIBehaviour, IButton,
|
||||
triggerName = transition.animationTriggers.disabledTrigger;
|
||||
break;
|
||||
default:
|
||||
tintColor = Color.black;
|
||||
transitionSprite = null;
|
||||
triggerName = string.Empty;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (transition.transition)
|
||||
@ -266,60 +318,83 @@ public class UXButton : UIBehaviour, IButton,
|
||||
DoSpriteSwap(transition, transitionSprite);
|
||||
break;
|
||||
case Selectable.Transition.Animation:
|
||||
TriggerAnimation(transition.animationTriggers, triggerName);
|
||||
TriggerAnimation(triggerName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void StartColorTween(TransitionData transitionData, Color targetColor, bool instant)
|
||||
private void StartColorTween(TransitionData data, Color targetColor, bool instant)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
transitionData.targetGraphic.CrossFadeColor(targetColor, instant ? 0f : transitionData.colors.fadeDuration, true, true);
|
||||
data.targetGraphic.CrossFadeColor(
|
||||
targetColor,
|
||||
instant ? 0f : data.colors.fadeDuration,
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
transitionData.targetGraphic.canvasRenderer.SetColor(targetColor);
|
||||
data.targetGraphic.canvasRenderer.SetColor(targetColor);
|
||||
}
|
||||
}
|
||||
|
||||
protected void DoSpriteSwap(TransitionData transitionData, Sprite newSprite)
|
||||
private void DoSpriteSwap(TransitionData data, Sprite newSprite)
|
||||
{
|
||||
if (transitionData.targetGraphic is Image image)
|
||||
if (data.targetGraphic is Image image)
|
||||
{
|
||||
image.overrideSprite = newSprite;
|
||||
}
|
||||
else if (transitionData.targetGraphic != null)
|
||||
}
|
||||
|
||||
private void TriggerAnimation(string trigger)
|
||||
{
|
||||
if (animator == null ||
|
||||
!animator.isActiveAndEnabled ||
|
||||
!animator.hasBoundPlayables ||
|
||||
string.IsNullOrEmpty(trigger))
|
||||
return;
|
||||
|
||||
foreach (var resetTrigger in _animResetTriggerIDs.Keys)
|
||||
{
|
||||
Log.Error($"Target Graphic must be Image for SpriteSwap. Object: {transitionData.targetGraphic.name}");
|
||||
animator.ResetTrigger(_animTriggerIDs[resetTrigger]);
|
||||
}
|
||||
|
||||
if (_animTriggerIDs.TryGetValue(trigger, out int id))
|
||||
{
|
||||
animator.SetTrigger(id);
|
||||
}
|
||||
}
|
||||
|
||||
void TriggerAnimation(AnimationTriggers animationTriggers, string triggername)
|
||||
private void AddTriggerID(string triggerName)
|
||||
{
|
||||
if (animator == null || !animator.isActiveAndEnabled || !animator.hasBoundPlayables || string.IsNullOrEmpty(triggername))
|
||||
return;
|
||||
|
||||
animator.ResetTrigger(animationTriggers.normalTrigger);
|
||||
animator.ResetTrigger(animationTriggers.highlightedTrigger);
|
||||
animator.ResetTrigger(animationTriggers.pressedTrigger);
|
||||
animator.ResetTrigger(animationTriggers.selectedTrigger);
|
||||
animator.ResetTrigger(animationTriggers.disabledTrigger);
|
||||
|
||||
animator.SetTrigger(triggername);
|
||||
if (!string.IsNullOrEmpty(triggerName))
|
||||
{
|
||||
int id = Animator.StringToHash(triggerName);
|
||||
if (!_animTriggerIDs.ContainsKey(triggerName))
|
||||
{
|
||||
_animTriggerIDs.Add(triggerName, id);
|
||||
_animResetTriggerIDs.Add(triggerName, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void PlayButtonSound(AudioClip clip)
|
||||
private void PlayButtonSound(AudioClip clip)
|
||||
{
|
||||
GameApp.Audio?.Play(AudioType.UISound, clip, false, GameApp.Audio.UISoundVolume);
|
||||
if (clip == null || GameApp.Audio == null) return;
|
||||
GameApp.Audio.Play(AudioType.UISound, clip, false, GameApp.Audio.UISoundVolume);
|
||||
}
|
||||
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
private IEnumerator OnFinishSubmit()
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
return;
|
||||
PlayButtonSound(clickAudioClip);
|
||||
ProcessClick();
|
||||
yield return _waitTimeFadeDuration;
|
||||
UpdateVisualState(
|
||||
m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal,
|
||||
false
|
||||
);
|
||||
_resetRoutine = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
// UXGroup.cs
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using System.Collections.Generic;
|
||||
@ -10,11 +8,12 @@ using UnityEngine.EventSystems;
|
||||
public class UXGroup : UIBehaviour
|
||||
{
|
||||
[SerializeField] private bool m_AllowSwitchOff;
|
||||
[ReadOnly] [SerializeField] private List<UXButton> m_Buttons = new List<UXButton>();
|
||||
[ReadOnly, SerializeField] private List<UXButton> m_Buttons = new();
|
||||
|
||||
private UXButton currentUXButton = null;
|
||||
private UXButton _current;
|
||||
private readonly HashSet<UXButton> _registeredButtons = new();
|
||||
|
||||
public UnityEvent<UXButton> onSelectedChanged = new UnityEvent<UXButton>();
|
||||
public UnityEvent<UXButton> onSelectedChanged = new();
|
||||
|
||||
public bool allowSwitchOff
|
||||
{
|
||||
@ -28,87 +27,83 @@ public class UXGroup : UIBehaviour
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
foreach (var button in _registeredButtons)
|
||||
{
|
||||
if (button) button.IsSelected = false;
|
||||
}
|
||||
m_Buttons.Clear();
|
||||
currentUXButton = null;
|
||||
_registeredButtons.Clear();
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
ValidateGroupState();
|
||||
}
|
||||
protected override void Awake() => ValidateGroupState();
|
||||
|
||||
public void RegisterButton(UXButton button)
|
||||
{
|
||||
if (!m_Buttons.Contains(button))
|
||||
if (!button || _registeredButtons.Contains(button)) return;
|
||||
|
||||
m_Buttons.Add(button);
|
||||
_registeredButtons.Add(button);
|
||||
|
||||
if (button.IsSelected)
|
||||
{
|
||||
m_Buttons.Add(button);
|
||||
if (button.IsSelected)
|
||||
{
|
||||
if (currentUXButton != null && currentUXButton != button)
|
||||
{
|
||||
currentUXButton.IsSelected = false;
|
||||
}
|
||||
currentUXButton = button;
|
||||
}
|
||||
ValidateGroupState();
|
||||
if (_current && _current != button)
|
||||
_current.IsSelected = false;
|
||||
_current = button;
|
||||
}
|
||||
|
||||
ValidateGroupState();
|
||||
}
|
||||
|
||||
public void UnregisterButton(UXButton button)
|
||||
{
|
||||
if (m_Buttons.Contains(button))
|
||||
{
|
||||
m_Buttons.Remove(button);
|
||||
button.IsSelected = false;
|
||||
}
|
||||
if (!button || !_registeredButtons.Contains(button)) return;
|
||||
|
||||
m_Buttons.Remove(button);
|
||||
_registeredButtons.Remove(button);
|
||||
button.IsSelected = false;
|
||||
|
||||
if (_current == button)
|
||||
_current = null;
|
||||
}
|
||||
|
||||
internal void NotifyButtonClicked(UXButton clickedButton)
|
||||
{
|
||||
if (!clickedButton.IsSelected)
|
||||
{
|
||||
SetSelectedButton(clickedButton);
|
||||
}
|
||||
else
|
||||
if (clickedButton.IsSelected)
|
||||
{
|
||||
if (m_AllowSwitchOff)
|
||||
SetSelectedButton(null);
|
||||
else if (currentUXButton != clickedButton)
|
||||
clickedButton.IsSelected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSelectedButton(clickedButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSelectedButton(UXButton targetButton)
|
||||
private void SetSelectedButton(UXButton target)
|
||||
{
|
||||
UXButton previousSelected = currentUXButton;
|
||||
currentUXButton = null; // 防止递归
|
||||
var previous = _current;
|
||||
_current = null;
|
||||
|
||||
foreach (var button in m_Buttons)
|
||||
{
|
||||
bool shouldSelect = (button == targetButton);
|
||||
bool shouldSelect = (button == target);
|
||||
if (button.IsSelected != shouldSelect)
|
||||
{
|
||||
button.IsSelected = shouldSelect;
|
||||
}
|
||||
if (shouldSelect) currentUXButton = button;
|
||||
|
||||
if (shouldSelect)
|
||||
_current = button;
|
||||
}
|
||||
|
||||
if (previousSelected != currentUXButton)
|
||||
{
|
||||
onSelectedChanged.Invoke(currentUXButton);
|
||||
}
|
||||
if (previous != _current)
|
||||
onSelectedChanged?.Invoke(_current);
|
||||
}
|
||||
|
||||
private void ValidateGroupState()
|
||||
{
|
||||
bool anySelected = m_Buttons.Exists(b => b.IsSelected);
|
||||
if (!anySelected && m_Buttons.Count > 0 && !m_AllowSwitchOff)
|
||||
{
|
||||
bool hasSelected = _current != null && _current.IsSelected;
|
||||
if (!hasSelected && m_Buttons.Count > 0 && !m_AllowSwitchOff)
|
||||
SetSelectedButton(m_Buttons[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public bool AnyOtherSelected(UXButton exclusion)
|
||||
@ -118,7 +113,6 @@ public class UXGroup : UIBehaviour
|
||||
if (button != exclusion && button.IsSelected)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user