2025-12-19 20:26:22 +08:00
|
|
|
using System;
|
|
|
|
|
using UnityEngine.Events;
|
|
|
|
|
using UnityEngine.EventSystems;
|
|
|
|
|
|
|
|
|
|
namespace UnityEngine.UI
|
|
|
|
|
{
|
|
|
|
|
[AddComponentMenu("UI/UXToggle", 30)]
|
|
|
|
|
[RequireComponent(typeof(RectTransform))]
|
|
|
|
|
public class UXToggle : UXSelectable, IPointerClickHandler, ISubmitHandler, ICanvasElement
|
|
|
|
|
{
|
|
|
|
|
[Serializable]
|
2025-12-22 13:41:19 +08:00
|
|
|
public class ToggleEvent : UnityEvent<bool>
|
|
|
|
|
{
|
|
|
|
|
}
|
2025-12-19 20:26:22 +08:00
|
|
|
|
|
|
|
|
public Toggle.ToggleTransition toggleTransition = Toggle.ToggleTransition.Fade;
|
|
|
|
|
public Graphic graphic;
|
|
|
|
|
|
|
|
|
|
[SerializeField] private UXGroup m_Group;
|
2025-12-22 13:41:19 +08:00
|
|
|
|
2025-12-19 20:26:22 +08:00
|
|
|
public UXGroup group
|
|
|
|
|
{
|
|
|
|
|
get { return m_Group; }
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
SetToggleGroup(value, true);
|
|
|
|
|
PlayEffect(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ToggleEvent onValueChanged = new ToggleEvent();
|
|
|
|
|
|
2025-12-22 13:41:19 +08:00
|
|
|
[Tooltip("Is the toggle currently on or off?")] [SerializeField]
|
|
|
|
|
private bool m_IsOn;
|
2025-12-19 20:26:22 +08:00
|
|
|
|
2025-12-22 13:41:19 +08:00
|
|
|
protected UXToggle()
|
|
|
|
|
{
|
|
|
|
|
}
|
2025-12-19 20:26:22 +08:00
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
protected override void OnValidate()
|
|
|
|
|
{
|
|
|
|
|
base.OnValidate();
|
|
|
|
|
|
|
|
|
|
if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
|
|
|
|
|
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public virtual void Rebuild(CanvasUpdate executing)
|
|
|
|
|
{
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
if (executing == CanvasUpdate.Prelayout)
|
|
|
|
|
onValueChanged.Invoke(m_IsOn);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-22 13:41:19 +08:00
|
|
|
public virtual void LayoutComplete()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void GraphicUpdateComplete()
|
|
|
|
|
{
|
|
|
|
|
}
|
2025-12-19 20:26:22 +08:00
|
|
|
|
|
|
|
|
protected override void OnDestroy()
|
|
|
|
|
{
|
|
|
|
|
if (m_Group != null)
|
|
|
|
|
m_Group.EnsureValidState();
|
|
|
|
|
base.OnDestroy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnEnable()
|
|
|
|
|
{
|
|
|
|
|
base.OnEnable();
|
|
|
|
|
PlayEffect(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnDidApplyAnimationProperties()
|
|
|
|
|
{
|
|
|
|
|
if (graphic != null)
|
|
|
|
|
{
|
|
|
|
|
bool oldValue = !Mathf.Approximately(graphic.canvasRenderer.GetColor().a, 0);
|
|
|
|
|
if (m_IsOn != oldValue)
|
|
|
|
|
{
|
|
|
|
|
m_IsOn = oldValue;
|
|
|
|
|
Set(!oldValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
base.OnDidApplyAnimationProperties();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-18 16:01:18 +08:00
|
|
|
|
2025-12-19 20:26:22 +08:00
|
|
|
private void SetToggleGroup(UXGroup newGroup, bool setMemberValue)
|
|
|
|
|
{
|
|
|
|
|
if (m_Group == newGroup)
|
|
|
|
|
{
|
|
|
|
|
if (setMemberValue)
|
|
|
|
|
m_Group = newGroup;
|
|
|
|
|
|
|
|
|
|
if (newGroup != null && !newGroup.ContainsToggle(this))
|
|
|
|
|
{
|
|
|
|
|
newGroup.RegisterToggle(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newGroup != null)
|
|
|
|
|
newGroup.EnsureValidState();
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_Group != null)
|
|
|
|
|
m_Group.UnregisterToggle(this);
|
|
|
|
|
|
|
|
|
|
if (setMemberValue)
|
|
|
|
|
m_Group = newGroup;
|
|
|
|
|
|
|
|
|
|
if (newGroup != null)
|
|
|
|
|
{
|
|
|
|
|
if (!newGroup.ContainsToggle(this))
|
|
|
|
|
{
|
|
|
|
|
newGroup.RegisterToggle(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isOn)
|
|
|
|
|
newGroup.NotifyToggleOn(this);
|
|
|
|
|
|
|
|
|
|
newGroup.EnsureValidState();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool isOn
|
|
|
|
|
{
|
|
|
|
|
get { return m_IsOn; }
|
|
|
|
|
set { Set(value); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetIsOnWithoutNotify(bool value)
|
|
|
|
|
{
|
|
|
|
|
Set(value, false);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-22 13:41:19 +08:00
|
|
|
protected override void DoStateTransition(Selectable.SelectionState state, bool instant)
|
|
|
|
|
{
|
|
|
|
|
if (state == Selectable.SelectionState.Disabled)
|
|
|
|
|
{
|
|
|
|
|
base.DoStateTransition(state, instant);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_IsOn)
|
|
|
|
|
state = Selectable.SelectionState.Selected;
|
|
|
|
|
|
|
|
|
|
base.DoStateTransition(state, instant);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-19 20:26:22 +08:00
|
|
|
void Set(bool value, bool sendCallback = true)
|
|
|
|
|
{
|
|
|
|
|
if (m_IsOn == value)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_IsOn = value;
|
|
|
|
|
if (m_Group != null && m_Group.isActiveAndEnabled && IsActive())
|
|
|
|
|
{
|
|
|
|
|
if (m_IsOn || (!m_Group.AnyTogglesOn() && !m_Group.allowSwitchOff))
|
|
|
|
|
{
|
|
|
|
|
m_IsOn = true;
|
|
|
|
|
m_Group.NotifyToggleOn(this, sendCallback);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PlayEffect(toggleTransition == Toggle.ToggleTransition.None);
|
2025-12-22 13:41:19 +08:00
|
|
|
|
2025-12-19 20:26:22 +08:00
|
|
|
if (sendCallback)
|
|
|
|
|
{
|
|
|
|
|
UISystemProfilerApi.AddMarker("Toggle.value", this);
|
|
|
|
|
onValueChanged.Invoke(m_IsOn);
|
|
|
|
|
}
|
2025-12-22 13:41:19 +08:00
|
|
|
|
|
|
|
|
bool instant = (toggleTransition == Toggle.ToggleTransition.None);
|
2026-03-18 16:01:18 +08:00
|
|
|
|
2025-12-22 13:41:19 +08:00
|
|
|
var stateToApply = m_IsOn ? Selectable.SelectionState.Selected : currentSelectionState;
|
|
|
|
|
DoStateTransition(stateToApply, instant);
|
2025-12-19 20:26:22 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-22 13:41:19 +08:00
|
|
|
|
2025-12-19 20:26:22 +08:00
|
|
|
private void PlayEffect(bool instant)
|
|
|
|
|
{
|
|
|
|
|
if (graphic == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
if (!Application.isPlaying)
|
|
|
|
|
graphic.canvasRenderer.SetAlpha(m_IsOn ? 1f : 0f);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
graphic.CrossFadeAlpha(m_IsOn ? 1f : 0f, instant ? 0f : 0.1f, true);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-22 13:41:19 +08:00
|
|
|
|
2025-12-19 20:26:22 +08:00
|
|
|
protected override void Start()
|
|
|
|
|
{
|
|
|
|
|
PlayEffect(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void InternalToggle()
|
|
|
|
|
{
|
|
|
|
|
if (!IsActive() || !IsInteractable())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
isOn = !isOn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void OnPointerEnter(PointerEventData eventData)
|
|
|
|
|
{
|
|
|
|
|
base.OnPointerEnter(eventData);
|
|
|
|
|
PlayAudio(hoverAudioClip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void OnPointerClick(PointerEventData eventData)
|
|
|
|
|
{
|
|
|
|
|
if (eventData.button != PointerEventData.InputButton.Left)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
InternalToggle();
|
|
|
|
|
PlayAudio(clickAudioClip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void OnSubmit(BaseEventData eventData)
|
|
|
|
|
{
|
|
|
|
|
InternalToggle();
|
|
|
|
|
PlayAudio(clickAudioClip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void PlayAudio(AudioClip clip)
|
|
|
|
|
{
|
|
|
|
|
if (clip && UXComponentExtensionsHelper.AudioHelper != null)
|
|
|
|
|
UXComponentExtensionsHelper.AudioHelper.PlayAudio(clip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[SerializeField] private AudioClip hoverAudioClip;
|
|
|
|
|
[SerializeField] private AudioClip clickAudioClip;
|
|
|
|
|
}
|
|
|
|
|
}
|