效果如下:

原理上面,其实就是一个Toggle,选中时改变圆点的位置,并将背景色改为绿色;未选中时,圆点回到默认位置,并将背景色改为默认色。
层级结构如下:

面板参数如下:



要注意两个地方:
- Toggle图片有红框的位置,要一致。
- 小圆点也就是Checkmark,锚点需要是居中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SwitchToggle : MonoBehaviour
{
//把手RectTransform
[SerializeField] private RectTransform handleRectTransform;
//把手开启颜色
[SerializeField] private Color _handleActiveColor;
//开关背景开启颜色
[SerializeField] private Color _backgroundActiveColor;
//动画时间
[SerializeField] private float _duration = 0.5f;
//开关背景与把手的图片
private Image _handleImage, _backgroundImage;
//开关背景与把手的默认颜色
private Color _handleColor, _backgroundColor;
//把手移动的位置
private Vector2 _handlePosition;
private Toggle _toggle;
private void Awake()
{
_toggle = GetComponent<Toggle>();
handleRectTransform = transform.Find("Background").Find("Checkmark").GetComponent<RectTransform>();
_handleImage = handleRectTransform.GetComponent<Image>();
_backgroundImage = handleRectTransform.parent.GetComponent<Image>();
_handleColor = _handleImage.color;
_backgroundColor = _backgroundImage.color;
_handlePosition = handleRectTransform.anchoredPosition;
_toggle.onValueChanged.AddListener(OnSwitch);
//在游戏对象启动时检查 _toggle 组件的初始选中状态,依据选中状态来执行OnSwitch方法函数
if (_toggle.isOn)
{
OnSwitch(true);
}
}
//控制开关动画方法函数
private void OnSwitch(bool on)
{
//没有Dotween插件使用下面的代码
if (on)
{
handleRectTransform.anchoredPosition = Vector2.MoveTowards(handleRectTransform.anchoredPosition, new Vector2(-_handlePosition.x, _handlePosition.y), _duration * 100);
}
else
handleRectTransform.anchoredPosition = Vector2.MoveTowards(handleRectTransform.anchoredPosition, new Vector2(_handlePosition.x, _handlePosition.y), _duration * 100);
if (on)
_backgroundImage.color = _backgroundActiveColor;
else
_backgroundImage.color = _backgroundColor;
if (on)
_handleImage.color = _handleActiveColor;
else
_handleImage.color = _handleColor; ;
//有Dotween插件时使用下面的代码
/handleRectTransform.DOAnchorPos(on ? -_handlePosition : _handlePosition, _duration).SetEase(Ease.InOutBack);
//_backgroundImage.DOColor(on ? _backgroundActiveColor : _backgroundColor, _duration).SetEase(Ease.InOutBack);
//_handleImage.DOColor(on ? _handleActiveColor : _handleColor, _duration).SetEase(Ease.InOutBack);
}
//避免持续监听 _toggle 的 onValueChanged 事件,防止在对象已销毁的情况下继续调用 OnSwitch 方法,避免潜在的错误或资源浪费
private void OnDestroy()
{
_toggle.onValueChanged.RemoveListener(OnSwitch);
}
}