// *********************************************************************** // Assembly : Unity // Author : Kimch // Created : // // Last Modified By : Kimch // Last Modified On : // *********************************************************************** // // // *********************************************************************** using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.Serialization; using UnityEngine.UI; /// /// Simple Switch -- something that has an 'on' and 'off' states: checkbox, Switch button, radio button, etc. /// [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 { } /// /// Transition type. /// public SwitchTransition switchTransition = SwitchTransition.Fade; /// /// Graphic the Switch should be working with. /// 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); } } } /// /// Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers. /// 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�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); } /// /// Whether the Switch is currently active. /// 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); } } /// /// Play the appropriate effect. /// 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); } /// /// Assume the correct visual state. /// protected override void Start() { PlayEffect(true); } private void InternalSwitch() { if (!IsActive() || !IsInteractable()) return; isOn = !isOn; } /// /// React to clicks. /// public virtual void OnPointerClick(PointerEventData eventData) { if (eventData.button != PointerEventData.InputButton.Left) return; InternalSwitch(); } public virtual void OnSubmit(BaseEventData eventData) { InternalSwitch(); } }