Files
2026-02-21 16:45:37 +08:00

199 lines
3.7 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace UIWidgets
{
public class Switch : Selectable, ISubmitHandler, IPointerClickHandler, IEventSystemHandler
{
[SerializeField]
protected bool isOn;
[SerializeField]
protected SwitchDirection direction;
[SerializeField]
public RectTransform Mark;
[SerializeField]
public Image Background;
[SerializeField]
private Color backgroundOnColor = new Color(1f, 1f, 1f, 1f);
[SerializeField]
private Color backgroundOffColor = new Color(1f, 43f / 51f, 23f / 51f, 1f);
[SerializeField]
public float AnimationDuration = 0.3f;
[SerializeField]
public SwitchEvent OnValueChanged = new SwitchEvent();
protected Coroutine CurrentCorutine;
public bool IsOn
{
get
{
return isOn;
}
set
{
if (isOn != value)
{
isOn = value;
Changed();
}
}
}
public SwitchDirection Direction
{
get
{
return direction;
}
set
{
direction = value;
SetMarkPosition(false);
}
}
public Color BackgroundOnColor
{
get
{
return backgroundOnColor;
}
set
{
backgroundOnColor = value;
SetBackgroundColor();
}
}
public Color BackgroundOffColor
{
get
{
return backgroundOffColor;
}
set
{
backgroundOffColor = value;
SetBackgroundColor();
}
}
protected virtual void Changed()
{
SetMarkPosition();
SetBackgroundColor();
OnValueChanged.Invoke(IsOn);
}
protected virtual void SetMarkPosition(bool animate = true)
{
if (CurrentCorutine != null)
{
StopCoroutine(CurrentCorutine);
}
if (animate)
{
StartCoroutine(AnimateSwitch(IsOn, AnimationDuration));
}
else
{
SetMarkPosition(GetPosition(IsOn));
}
}
protected virtual IEnumerator AnimateSwitch(bool state, float time)
{
SetMarkPosition(GetPosition(!IsOn));
float prev_position = GetPosition(!IsOn);
float next_position = GetPosition(IsOn);
float end_time = Time.time + time;
while (Time.time <= end_time)
{
float distance = 1f - (end_time - Time.time) / time;
float pos = Mathf.Lerp(prev_position, next_position, distance);
SetMarkPosition(pos);
yield return null;
}
SetMarkPosition(GetPosition(IsOn));
}
protected virtual void SetMarkPosition(float position)
{
if (!(Mark == null))
{
if (IsHorizontal())
{
Mark.anchorMin = new Vector2(position, Mark.anchorMin.y);
Mark.anchorMax = new Vector2(position, Mark.anchorMax.y);
Mark.pivot = new Vector2(position, Mark.pivot.y);
}
else
{
Mark.anchorMin = new Vector2(Mark.anchorMin.x, position);
Mark.anchorMax = new Vector2(Mark.anchorMax.x, position);
Mark.pivot = new Vector2(Mark.pivot.x, position);
}
}
}
protected bool IsHorizontal()
{
return Direction == SwitchDirection.LeftToRight || Direction == SwitchDirection.RightToLeft;
}
protected float GetPosition(bool state)
{
switch (Direction)
{
case SwitchDirection.LeftToRight:
case SwitchDirection.BottomToTop:
return (!state) ? 0f : 1f;
case SwitchDirection.RightToLeft:
case SwitchDirection.TopToBottom:
return (!state) ? 1f : 0f;
default:
return 0f;
}
}
protected virtual void SetBackgroundColor()
{
if (!(Background == null))
{
Background.color = ((!IsOn) ? BackgroundOffColor : BackgroundOnColor);
}
}
protected virtual void CallChanged()
{
if (IsActive() && IsInteractable())
{
IsOn = !IsOn;
}
}
public virtual void OnSubmit(BaseEventData eventData)
{
CallChanged();
}
public virtual void OnPointerClick(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
CallChanged();
}
}
}
}