com.alicizax.unity.ui.exten.../Runtime/UXComponent/Group/UXToggle.cs
陈思海 551423f09d 大优化
大优化 懒得写了 重构了分离了 UXButton UXToggle UXSelectable UXGroup
2025-12-19 20:26:22 +08:00

261 lines
7.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
#if INPUTSYSTEM_SUPPORT
using UnityEngine.InputSystem;
#endif
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.UI
{
[AddComponentMenu("UI/UXToggle", 30)]
[RequireComponent(typeof(RectTransform))]
public class UXToggle : UXSelectable, IPointerClickHandler, ISubmitHandler, ICanvasElement
#if INPUTSYSTEM_SUPPORT
, IHotkeyTrigger
#endif
{
[Serializable]
public class ToggleEvent : UnityEvent<bool> { }
public Toggle.ToggleTransition toggleTransition = Toggle.ToggleTransition.Fade;
public Graphic graphic;
[SerializeField] private UXGroup m_Group;
public UXGroup group
{
get { return m_Group; }
set
{
SetToggleGroup(value, true);
PlayEffect(true);
}
}
public ToggleEvent onValueChanged = new ToggleEvent();
[Tooltip("Is the toggle currently on or off?")]
[SerializeField] private bool m_IsOn;
protected UXToggle() { }
#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
}
public virtual void LayoutComplete() { }
public virtual void GraphicUpdateComplete() { }
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();
}
// Centralized group setter logic.
private void SetToggleGroup(UXGroup newGroup, bool setMemberValue)
{
// 如果组没有改变,仍然需要确保组里包含此 toggle修复编辑器中批量拖拽只注册最后一项的问题
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;
// 注册到新组(不再强依赖 IsActive(),以保证编辑器批量赋值时也能正确注册)
if (newGroup != null)
{
if (!newGroup.ContainsToggle(this))
{
newGroup.RegisterToggle(this);
}
// 如果正在 on通知组维持单选逻辑
if (isOn)
newGroup.NotifyToggleOn(this);
// 同步组的内部状态,确保 Inspector 列表正确显示
newGroup.EnsureValidState();
}
}
public bool isOn
{
get { return m_IsOn; }
set { Set(value); }
}
public void SetIsOnWithoutNotify(bool value)
{
Set(value, false);
}
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);
if (sendCallback)
{
UISystemProfilerApi.AddMarker("Toggle.value", this);
onValueChanged.Invoke(m_IsOn);
}
}
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);
}
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);
}
#if INPUTSYSTEM_SUPPORT
InputActionReference IHotkeyTrigger.HotkeyAction
{
get => _hotkeyAction;
set => _hotkeyAction = value;
}
EHotkeyPressType IHotkeyTrigger.HotkeyPressType
{
get => _hotkeyPressType;
set => _hotkeyPressType = value;
}
void IHotkeyTrigger.HotkeyActionTrigger()
{
if (interactable)
{
OnSubmit(null);
}
}
[SerializeField] internal InputActionReference _hotkeyAction;
[SerializeField] internal EHotkeyPressType _hotkeyPressType;
public InputActionReference HotKeyRefrence
{
get { return _hotkeyAction; }
}
#endif
[SerializeField] private AudioClip hoverAudioClip;
[SerializeField] private AudioClip clickAudioClip;
}
}