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_ImagePosition: 0
|
||||||
m_ContentOffset: {x: 15, y: 1}
|
m_ContentOffset: {x: 15, y: 1}
|
||||||
m_FixedWidth: 24
|
m_FixedWidth: 24
|
||||||
m_FixedHeight: 15
|
m_FixedHeight: 24
|
||||||
m_StretchWidth: 1
|
m_StretchWidth: 1
|
||||||
m_StretchHeight: 0
|
m_StretchHeight: 0
|
||||||
m_label:
|
m_label:
|
||||||
|
@ -9,7 +9,7 @@ using UnityEngine.UI;
|
|||||||
|
|
||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
[CustomEditor(typeof(UXButton), true)]
|
[CustomEditor(typeof(UXButton), true)]
|
||||||
public class UXButtonEditor : Editor
|
internal class UXButtonEditor : Editor
|
||||||
{
|
{
|
||||||
private enum TabType
|
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
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
icon: {instanceID: 0}
|
icon: {fileID: 2800000, guid: c4398d454b1a861499ef73d23bc7a032, type: 3}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AlicizaX;
|
using AlicizaX;
|
||||||
using AlicizaX.UI.Extension;
|
using AlicizaX.UI.Extension;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.Serialization;
|
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using AudioType = AlicizaX.Audio.Runtime.AudioType;
|
using AudioType = AlicizaX.Audio.Runtime.AudioType;
|
||||||
|
|
||||||
@ -16,7 +16,6 @@ public enum ButtonModeType
|
|||||||
Toggle
|
Toggle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
public class TransitionData
|
public class TransitionData
|
||||||
{
|
{
|
||||||
@ -24,102 +23,130 @@ public class TransitionData
|
|||||||
public Selectable.Transition transition = Selectable.Transition.ColorTint;
|
public Selectable.Transition transition = Selectable.Transition.ColorTint;
|
||||||
public ColorBlock colors;
|
public ColorBlock colors;
|
||||||
public SpriteState spriteState;
|
public SpriteState spriteState;
|
||||||
public AnimationTriggers animationTriggers = new AnimationTriggers();
|
public AnimationTriggers animationTriggers = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal enum SelectionState
|
internal enum SelectionState
|
||||||
{
|
{
|
||||||
Normal,
|
Normal,
|
||||||
|
|
||||||
Highlighted,
|
Highlighted,
|
||||||
|
|
||||||
Pressed,
|
Pressed,
|
||||||
|
|
||||||
Selected,
|
Selected,
|
||||||
Disabled,
|
Disabled,
|
||||||
}
|
}
|
||||||
|
[ExecuteInEditMode]
|
||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
public class UXButton : UIBehaviour, IButton,
|
public class UXButton : UIBehaviour, IButton,
|
||||||
IPointerDownHandler,
|
IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler,
|
||||||
IPointerUpHandler,
|
IPointerExitHandler, IPointerClickHandler, ISubmitHandler
|
||||||
IPointerEnterHandler,
|
|
||||||
IPointerExitHandler,
|
|
||||||
IPointerClickHandler
|
|
||||||
{
|
{
|
||||||
|
#region Serialized Fields
|
||||||
|
|
||||||
[SerializeField] private bool m_Interactable = true;
|
[SerializeField] private bool m_Interactable = true;
|
||||||
|
|
||||||
[SerializeField] private ButtonModeType m_Mode;
|
[SerializeField] private ButtonModeType m_Mode;
|
||||||
|
[SerializeField] private Button.ButtonClickedEvent m_OnClick = new();
|
||||||
[SerializeField] private Button.ButtonClickedEvent m_OnClick = new Button.ButtonClickedEvent();
|
[SerializeField] private TransitionData m_TransitionData = new();
|
||||||
|
[SerializeField] private List<TransitionData> m_ChildTransitions = new();
|
||||||
[SerializeField] private TransitionData m_TransitionData = new TransitionData();
|
|
||||||
|
|
||||||
[SerializeField] private List<TransitionData> m_ChildTransitions = new List<TransitionData>();
|
|
||||||
[SerializeField] private UXGroup m_UXGroup;
|
[SerializeField] private UXGroup m_UXGroup;
|
||||||
|
|
||||||
[SerializeField] private AudioClip hoverAudioClip;
|
[SerializeField] private AudioClip hoverAudioClip;
|
||||||
[SerializeField] private AudioClip clickAudioClip;
|
[SerializeField] private AudioClip clickAudioClip;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private Variables
|
||||||
|
|
||||||
[SerializeField] private SelectionState m_SelectionState = SelectionState.Normal;
|
[SerializeField] private SelectionState m_SelectionState = SelectionState.Normal;
|
||||||
private bool m_DownAndExistUI;
|
private bool m_DownAndExistUI;
|
||||||
private bool m_IsDown;
|
private bool m_IsDown;
|
||||||
private bool m_IsTogSelected;
|
private bool m_IsTogSelected;
|
||||||
|
|
||||||
private Animator _animator;
|
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
|
internal Animator animator
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
_animator = _animator ?? GetComponent<Animator>();
|
if (!_animator)
|
||||||
|
_animator = GetComponent<Animator>();
|
||||||
return _animator;
|
return _animator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSelected
|
public bool IsSelected
|
||||||
{
|
{
|
||||||
get { return m_IsTogSelected; }
|
get => m_IsTogSelected;
|
||||||
internal set
|
internal set
|
||||||
{
|
{
|
||||||
|
if (m_IsTogSelected == value) return;
|
||||||
m_IsTogSelected = value;
|
m_IsTogSelected = value;
|
||||||
onValueChanged?.Invoke(m_IsTogSelected);
|
onValueChanged?.Invoke(m_IsTogSelected);
|
||||||
m_SelectionState = m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal;
|
m_SelectionState = value ? SelectionState.Selected : SelectionState.Normal;
|
||||||
UpdateVisualState(m_SelectionState, false);
|
UpdateVisualState(m_SelectionState, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Button.ButtonClickedEvent onClick
|
public Button.ButtonClickedEvent onClick
|
||||||
{
|
{
|
||||||
get { return m_OnClick; }
|
get => m_OnClick;
|
||||||
set { m_OnClick = value; }
|
set => m_OnClick = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SerializeField] private UnityEvent<bool> m_OnValueChanged = new UnityEvent<bool>();
|
[SerializeField] private UnityEvent<bool> m_OnValueChanged = new();
|
||||||
|
|
||||||
public UnityEvent<bool> onValueChanged
|
public UnityEvent<bool> onValueChanged
|
||||||
{
|
{
|
||||||
get { return m_OnValueChanged; }
|
get => m_OnValueChanged;
|
||||||
set { m_OnValueChanged = value; }
|
set => m_OnValueChanged = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Unity Lifecycle
|
||||||
|
|
||||||
protected override void Awake()
|
protected override void Awake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
base.Awake();
|
||||||
if (m_Mode == ButtonModeType.Toggle)
|
_waitTimeFadeDuration = new WaitForSeconds(
|
||||||
{
|
Mathf.Max(0.01f, m_TransitionData.colors.fadeDuration));
|
||||||
onValueChanged?.Invoke(IsSelected);
|
|
||||||
}
|
var triggers = m_TransitionData.animationTriggers;
|
||||||
|
AddTriggerID(triggers.normalTrigger);
|
||||||
|
AddTriggerID(triggers.highlightedTrigger);
|
||||||
|
AddTriggerID(triggers.pressedTrigger);
|
||||||
|
AddTriggerID(triggers.selectedTrigger);
|
||||||
|
AddTriggerID(triggers.disabledTrigger);
|
||||||
|
|
||||||
UpdateVisualState(m_SelectionState, true);
|
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)
|
void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
if (!m_Interactable) return;
|
if (!ShouldProcessEvent(eventData)) return;
|
||||||
if (eventData.button != PointerEventData.InputButton.Left) return;
|
|
||||||
m_IsDown = true;
|
m_IsDown = true;
|
||||||
m_SelectionState = SelectionState.Pressed;
|
m_SelectionState = SelectionState.Pressed;
|
||||||
UpdateVisualState(m_SelectionState, false);
|
UpdateVisualState(m_SelectionState, false);
|
||||||
@ -127,29 +154,30 @@ public class UXButton : UIBehaviour, IButton,
|
|||||||
|
|
||||||
void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
|
void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
if (!m_Interactable) return;
|
if (!m_Interactable || eventData.button != PointerEventData.InputButton.Left)
|
||||||
|
return;
|
||||||
|
|
||||||
m_IsDown = false;
|
m_IsDown = false;
|
||||||
|
if (m_IsTogSelected)
|
||||||
if (!m_IsTogSelected)
|
|
||||||
{
|
{
|
||||||
m_SelectionState = m_DownAndExistUI ? SelectionState.Normal : SelectionState.Highlighted;
|
m_SelectionState = SelectionState.Selected;
|
||||||
UpdateVisualState(m_SelectionState, false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_SelectionState = SelectionState.Selected;
|
m_SelectionState = m_DownAndExistUI ? SelectionState.Normal : SelectionState.Highlighted;
|
||||||
UpdateVisualState(m_SelectionState, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateVisualState(m_SelectionState, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
|
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
if (!m_Interactable || CantTouch()) return;
|
if (!ShouldProcessEvent(eventData)) return;
|
||||||
|
|
||||||
m_SelectionState = SelectionState.Highlighted;
|
|
||||||
m_DownAndExistUI = false;
|
m_DownAndExistUI = false;
|
||||||
if (m_IsDown) return;
|
if (m_IsDown) return;
|
||||||
|
|
||||||
|
m_SelectionState = SelectionState.Highlighted;
|
||||||
UpdateVisualState(m_SelectionState, false);
|
UpdateVisualState(m_SelectionState, false);
|
||||||
PlayButtonSound(hoverAudioClip);
|
PlayButtonSound(hoverAudioClip);
|
||||||
}
|
}
|
||||||
@ -163,45 +191,72 @@ public class UXButton : UIBehaviour, IButton,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CantTouch())
|
m_SelectionState = IsSelected ? SelectionState.Selected : SelectionState.Normal;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_SelectionState = SelectionState.Normal;
|
|
||||||
|
|
||||||
UpdateVisualState(m_SelectionState, false);
|
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)
|
public void SetSelect(bool state, bool boardEvent = false)
|
||||||
{
|
{
|
||||||
if (m_Mode != ButtonModeType.Toggle) return;
|
if (m_Mode != ButtonModeType.Toggle) return;
|
||||||
m_IsTogSelected = state;
|
_boardEvent = boardEvent;
|
||||||
if (boardEvent) onValueChanged?.Invoke(m_IsTogSelected);
|
IsSelected = state;
|
||||||
m_SelectionState = m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal;
|
}
|
||||||
UpdateVisualState(m_SelectionState, false);
|
|
||||||
|
#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()
|
private void ProcessClick()
|
||||||
{
|
{
|
||||||
|
if (!_boardEvent)
|
||||||
|
{
|
||||||
|
_boardEvent = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_boardEvent = true;
|
||||||
if (m_Mode == ButtonModeType.Normal)
|
if (m_Mode == ButtonModeType.Normal)
|
||||||
{
|
{
|
||||||
UISystemProfilerApi.AddMarker("Button.onClick", this);
|
UISystemProfilerApi.AddMarker("Button.onClick", this);
|
||||||
onClick?.Invoke();
|
m_OnClick?.Invoke();
|
||||||
|
}
|
||||||
|
else if (m_UXGroup)
|
||||||
|
{
|
||||||
|
m_UXGroup.NotifyButtonClicked(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_UXGroup)
|
|
||||||
{
|
|
||||||
m_UXGroup.NotifyButtonClicked(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsSelected = !IsSelected;
|
IsSelected = !IsSelected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +270,6 @@ public class UXButton : UIBehaviour, IButton,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ProcessTransitionData(TransitionData transition, SelectionState state, bool instant)
|
private void ProcessTransitionData(TransitionData transition, SelectionState state, bool instant)
|
||||||
{
|
{
|
||||||
if (transition.targetGraphic == null) return;
|
if (transition.targetGraphic == null) return;
|
||||||
@ -223,11 +277,12 @@ public class UXButton : UIBehaviour, IButton,
|
|||||||
Color tintColor;
|
Color tintColor;
|
||||||
Sprite transitionSprite;
|
Sprite transitionSprite;
|
||||||
string triggerName;
|
string triggerName;
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case SelectionState.Normal:
|
case SelectionState.Normal:
|
||||||
tintColor = transition.colors.normalColor;
|
tintColor = transition.colors.normalColor;
|
||||||
transitionSprite = null;
|
transitionSprite = transition.spriteState.highlightedSprite;
|
||||||
triggerName = transition.animationTriggers.normalTrigger;
|
triggerName = transition.animationTriggers.normalTrigger;
|
||||||
break;
|
break;
|
||||||
case SelectionState.Highlighted:
|
case SelectionState.Highlighted:
|
||||||
@ -251,10 +306,7 @@ public class UXButton : UIBehaviour, IButton,
|
|||||||
triggerName = transition.animationTriggers.disabledTrigger;
|
triggerName = transition.animationTriggers.disabledTrigger;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
tintColor = Color.black;
|
return;
|
||||||
transitionSprite = null;
|
|
||||||
triggerName = string.Empty;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (transition.transition)
|
switch (transition.transition)
|
||||||
@ -266,60 +318,83 @@ public class UXButton : UIBehaviour, IButton,
|
|||||||
DoSpriteSwap(transition, transitionSprite);
|
DoSpriteSwap(transition, transitionSprite);
|
||||||
break;
|
break;
|
||||||
case Selectable.Transition.Animation:
|
case Selectable.Transition.Animation:
|
||||||
TriggerAnimation(transition.animationTriggers, triggerName);
|
TriggerAnimation(triggerName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void StartColorTween(TransitionData transitionData, Color targetColor, bool instant)
|
private void StartColorTween(TransitionData data, Color targetColor, bool instant)
|
||||||
{
|
{
|
||||||
if (Application.isPlaying)
|
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
|
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;
|
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))
|
if (!string.IsNullOrEmpty(triggerName))
|
||||||
return;
|
{
|
||||||
|
int id = Animator.StringToHash(triggerName);
|
||||||
animator.ResetTrigger(animationTriggers.normalTrigger);
|
if (!_animTriggerIDs.ContainsKey(triggerName))
|
||||||
animator.ResetTrigger(animationTriggers.highlightedTrigger);
|
{
|
||||||
animator.ResetTrigger(animationTriggers.pressedTrigger);
|
_animTriggerIDs.Add(triggerName, id);
|
||||||
animator.ResetTrigger(animationTriggers.selectedTrigger);
|
_animResetTriggerIDs.Add(triggerName, id);
|
||||||
animator.ResetTrigger(animationTriggers.disabledTrigger);
|
}
|
||||||
|
}
|
||||||
animator.SetTrigger(triggername);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerator OnFinishSubmit()
|
||||||
public void OnPointerClick(PointerEventData eventData)
|
|
||||||
{
|
{
|
||||||
if (eventData.button != PointerEventData.InputButton.Left)
|
yield return _waitTimeFadeDuration;
|
||||||
return;
|
UpdateVisualState(
|
||||||
PlayButtonSound(clickAudioClip);
|
m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal,
|
||||||
ProcessClick();
|
false
|
||||||
|
);
|
||||||
|
_resetRoutine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// UXGroup.cs
|
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -10,11 +8,12 @@ using UnityEngine.EventSystems;
|
|||||||
public class UXGroup : UIBehaviour
|
public class UXGroup : UIBehaviour
|
||||||
{
|
{
|
||||||
[SerializeField] private bool m_AllowSwitchOff;
|
[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
|
public bool allowSwitchOff
|
||||||
{
|
{
|
||||||
@ -28,87 +27,83 @@ public class UXGroup : UIBehaviour
|
|||||||
|
|
||||||
protected override void OnDestroy()
|
protected override void OnDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
foreach (var button in _registeredButtons)
|
||||||
|
{
|
||||||
|
if (button) button.IsSelected = false;
|
||||||
|
}
|
||||||
m_Buttons.Clear();
|
m_Buttons.Clear();
|
||||||
currentUXButton = null;
|
_registeredButtons.Clear();
|
||||||
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Awake() => ValidateGroupState();
|
||||||
protected override void Awake()
|
|
||||||
{
|
|
||||||
base.Awake();
|
|
||||||
ValidateGroupState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterButton(UXButton button)
|
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 (_current && _current != button)
|
||||||
if (button.IsSelected)
|
_current.IsSelected = false;
|
||||||
{
|
_current = button;
|
||||||
if (currentUXButton != null && currentUXButton != button)
|
|
||||||
{
|
|
||||||
currentUXButton.IsSelected = false;
|
|
||||||
}
|
|
||||||
currentUXButton = button;
|
|
||||||
}
|
|
||||||
ValidateGroupState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValidateGroupState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnregisterButton(UXButton button)
|
public void UnregisterButton(UXButton button)
|
||||||
{
|
{
|
||||||
if (m_Buttons.Contains(button))
|
if (!button || !_registeredButtons.Contains(button)) return;
|
||||||
{
|
|
||||||
m_Buttons.Remove(button);
|
m_Buttons.Remove(button);
|
||||||
button.IsSelected = false;
|
_registeredButtons.Remove(button);
|
||||||
}
|
button.IsSelected = false;
|
||||||
|
|
||||||
|
if (_current == button)
|
||||||
|
_current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void NotifyButtonClicked(UXButton clickedButton)
|
internal void NotifyButtonClicked(UXButton clickedButton)
|
||||||
{
|
{
|
||||||
if (!clickedButton.IsSelected)
|
if (clickedButton.IsSelected)
|
||||||
{
|
|
||||||
SetSelectedButton(clickedButton);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (m_AllowSwitchOff)
|
if (m_AllowSwitchOff)
|
||||||
SetSelectedButton(null);
|
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;
|
var previous = _current;
|
||||||
currentUXButton = null; // 防止递归
|
_current = null;
|
||||||
|
|
||||||
foreach (var button in m_Buttons)
|
foreach (var button in m_Buttons)
|
||||||
{
|
{
|
||||||
bool shouldSelect = (button == targetButton);
|
bool shouldSelect = (button == target);
|
||||||
if (button.IsSelected != shouldSelect)
|
if (button.IsSelected != shouldSelect)
|
||||||
{
|
|
||||||
button.IsSelected = shouldSelect;
|
button.IsSelected = shouldSelect;
|
||||||
}
|
|
||||||
if (shouldSelect) currentUXButton = button;
|
if (shouldSelect)
|
||||||
|
_current = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousSelected != currentUXButton)
|
if (previous != _current)
|
||||||
{
|
onSelectedChanged?.Invoke(_current);
|
||||||
onSelectedChanged.Invoke(currentUXButton);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateGroupState()
|
private void ValidateGroupState()
|
||||||
{
|
{
|
||||||
bool anySelected = m_Buttons.Exists(b => b.IsSelected);
|
bool hasSelected = _current != null && _current.IsSelected;
|
||||||
if (!anySelected && m_Buttons.Count > 0 && !m_AllowSwitchOff)
|
if (!hasSelected && m_Buttons.Count > 0 && !m_AllowSwitchOff)
|
||||||
{
|
|
||||||
SetSelectedButton(m_Buttons[0]);
|
SetSelectedButton(m_Buttons[0]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AnyOtherSelected(UXButton exclusion)
|
public bool AnyOtherSelected(UXButton exclusion)
|
||||||
@ -118,7 +113,6 @@ public class UXGroup : UIBehaviour
|
|||||||
if (button != exclusion && button.IsSelected)
|
if (button != exclusion && button.IsSelected)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user