2025-05-18 01:04:31 +08:00

260 lines
7.6 KiB
C#
Raw Blame History

// ***********************************************************************
// Assembly : Unity
// Author : Kimch
// Created :
//
// Last Modified By : Kimch
// Last Modified On :
// ***********************************************************************
// <copyright file= "KUISwitch" company=""></copyright>
// <summary></summary>
// ***********************************************************************
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;
/// <summary>
/// Simple Switch -- something that has an 'on' and 'off' states: checkbox, Switch button, radio button, etc.
/// </summary>
[AddComponentMenu("UI/Custom/Switch", 31)]
[RequireComponent(typeof(RectTransform))]
public class KUISwitch : Selectable, IPointerClickHandler, ISubmitHandler, ICanvasElement
{
public enum SwitchTransition
{
None,
Fade
}
[Serializable]
public class SwitchEvent : UnityEvent<bool>
{ }
/// <summary>
/// Transition type.
/// </summary>
public SwitchTransition switchTransition = SwitchTransition.Fade;
/// <summary>
/// Graphic the Switch should be working with.
/// </summary>
public Graphic onGraphic;
public Graphic offGraphic;
// group that this Switch can belong to
[SerializeField]
private KUISwitchGroup m_Group;
public KUISwitchGroup group
{
get { return m_Group; }
set
{
m_Group = value;
#if UNITY_EDITOR
if (Application.isPlaying)
#endif
{
SetSwitchGroup(m_Group, true);
PlayEffect(true);
}
}
}
/// <summary>
/// Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
/// </summary>
public SwitchEvent onValueChanged = new SwitchEvent();
// Whether the Switch is on
[FormerlySerializedAs("m_IsActive")]
[Tooltip("Is the Switch currently on or off?")]
[SerializeField]
private bool m_IsOn;
protected KUISwitch()
{ }
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
#pragma warning disable CS0618 // “PrefabUtility.GetPrefabType(Object)”已过时:“Use GetPrefabAssetType and GetPrefabInstanceStatus to get the full picture about Prefab types.”
var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this);
#pragma warning restore CS0618 // “PrefabUtility.GetPrefabType(Object)”已过时:“Use GetPrefabAssetType and GetPrefabInstanceStatus to get the full picture about Prefab types.”
#pragma warning disable CS0618 // “PrefabType”已过时:“PrefabType no longer tells everything about Prefab instance.”
if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying)
#pragma warning restore CS0618 // “PrefabType”已过时:“PrefabType no longer tells everything about Prefab instance.”
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
}
#endif // if UNITY_EDITOR
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 OnEnable()
{
base.OnEnable();
SetSwitchGroup(m_Group, false);
PlayEffect(true);
}
protected override void OnDisable()
{
SetSwitchGroup(null, false);
base.OnDisable();
}
protected override void OnDidApplyAnimationProperties()
{
// Check if isOn has been changed by the animation.
// Unfortunately there is no way to check if we don<6F>t have a graphic.
//if (onGraphic != null)
//{
// bool oldValue = !Mathf.Approximately(onGraphic.canvasRenderer.GetColor().a, 0);
// if (m_IsOn != oldValue)
// {
// m_IsOn = oldValue;
// Set(!oldValue);
// }
//}
base.OnDidApplyAnimationProperties();
}
private void SetSwitchGroup(KUISwitchGroup newGroup, bool setMemberValue)
{
KUISwitchGroup oldGroup = m_Group;
// Sometimes IsActive returns false in OnDisable so don't check for it.
// Rather remove the Switch too often than too little.
if (m_Group != null)
m_Group.UnregisterSwitch(this);
// At runtime the group variable should be set but not when calling this method from OnEnable or OnDisable.
// That's why we use the setMemberValue parameter.
if (setMemberValue)
m_Group = newGroup;
// Only register to the new group if this Switch is active.
if (newGroup != null && IsActive())
newGroup.RegisterSwitch(this);
// If we are in a new group, and this Switch is on, notify group.
// Note: Don't refer to m_Group here as it's not guaranteed to have been set.
if (newGroup != null && newGroup != oldGroup && isOn && IsActive())
newGroup.NotifySwitchOn(this);
}
/// <summary>
/// Whether the Switch is currently active.
/// </summary>
public bool isOn
{
get { return m_IsOn; }
set
{
Set(value);
}
}
void Set(bool value)
{
Set(value, true);
}
void Set(bool value, bool sendCallback)
{
if (m_IsOn == value)
return;
// if we are in a group and set to true, do group logic
m_IsOn = value;
if (m_Group != null && IsActive())
{
if (m_IsOn || (!m_Group.AnySwitchsOn() && !m_Group.allowSwitchOff))
{
m_IsOn = true;
m_Group.NotifySwitchOn(this);
}
}
// Always send event when Switch is clicked, even if value didn't change
// due to already active Switch in a Switch group being clicked.
// Controls like Dropdown rely on this.
// It's up to the user to ignore a selection being set to the same value it already was, if desired.
PlayEffect(switchTransition == SwitchTransition.None);
if (sendCallback)
{
UISystemProfilerApi.AddMarker("Switch.value", this);
onValueChanged.Invoke(m_IsOn);
}
}
/// <summary>
/// Play the appropriate effect.
/// </summary>
private void PlayEffect(bool instant)
{
if (onGraphic == null || offGraphic == null)
return;
onGraphic.gameObject.SetActive(m_IsOn);
offGraphic.gameObject.SetActive(!m_IsOn);
//#if UNITY_EDITOR
// if (!Application.isPlaying)
// onGraphic.canvasRenderer.SetAlpha(m_IsOn ? 1f : 0f);
// else
//#endif
// onGraphic.CrossFadeAlpha(m_IsOn ? 1f : 0f, instant ? 0f : 0.1f, true);
}
/// <summary>
/// Assume the correct visual state.
/// </summary>
protected override void Start()
{
PlayEffect(true);
}
private void InternalSwitch()
{
if (!IsActive() || !IsInteractable())
return;
isOn = !isOn;
}
/// <summary>
/// React to clicks.
/// </summary>
public virtual void OnPointerClick(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left)
return;
InternalSwitch();
}
public virtual void OnSubmit(BaseEventData eventData)
{
InternalSwitch();
}
}