Unity UI动效 - Toggle切换动画


简介

如下图所示,当ToggleOnValueChanged事件执行时,会播放相应的切换动画,该功能可以通过Animation Editor编辑帧动画来实现,而本文介绍如何通过代码实现。

Toggle切换动画

实现

Off & On

using UnityEngine;
using UnityEngine.UI;

namespace SK.Framework.UI
{
    
    
    [RequireComponent(typeof(Toggle))]
    public class ToggleAnimation : MonoBehaviour
    {
    
    
        [SerializeField] private RectTransform off;
        [SerializeField] private RectTransform on;
    }
}

Off & On

OnValueChanged

为Toggle添加值变更事件:

using UnityEngine;
using UnityEngine.UI;

namespace SK.Framework.UI
{
    
    
    [RequireComponent(typeof(Toggle))]
    public class ToggleAnimation : MonoBehaviour
    {
    
    
        [SerializeField] private RectTransform off;
        [SerializeField] private RectTransform on;

        private Toggle toggle;

        private void Awake()
        {
    
    
            toggle = GetComponent<Toggle>();
            toggle.onValueChanged.AddListener(OnValueChanged);
        }

        private void OnValueChanged(bool isOn)
        {
    
    
			//TODO:
        }
    }
}

Start、Stop Coroutine

动画的切换过程在协程中实现,当值变更时,判断当前若正在运行协程,将其终止,然后开启相应的Switch2OnSwitch2Off动画:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

namespace SK.Framework.UI
{
    
    
    [RequireComponent(typeof(Toggle))]
    public class ToggleAnimation : MonoBehaviour
    {
    
    
        [SerializeField] private RectTransform off;
        [SerializeField] private RectTransform on;

        private Toggle toggle;
        private Coroutine coroutine;

        private void Awake()
        {
    
    
            toggle = GetComponent<Toggle>();
            toggle.onValueChanged.AddListener(OnValueChanged);
        }

        private void OnValueChanged(bool isOn)
        {
    
    
            if (coroutine != null)
                StopCoroutine(coroutine);

            coroutine = isOn ? StartCoroutine(Switch2OnCoroutine()) 
            : StartCoroutine(Switch2OffCoroutine());
        }

        private IEnumerator Switch2OnCoroutine()
        {
    
    
			//TODO:
        }

        private IEnumerator Switch2OffCoroutine()
        {
    
    
			//TODO:
        }
    }
}

Switch Animation

声明float类型变量,用于标识动画的时长,动画开始时,记录开始时间,当Time.time减去该开始时间小等于动画时长时,在for循环中通过插值运算计算相应的坐标:

float beginTime = Time.time;
for (; Time.time - beginTime <= duration;)
{
    
    
    float t = (Time.time - beginTime) / duration;
    on.position = Vector3.Lerp(offPosition, onPosition, t);
    yield return null;
}
on.position = onPosition;
coroutine = null;

完整代码:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

namespace SK.Framework.UI
{
    
    
    [RequireComponent(typeof(Toggle))]
    public class ToggleAnimation : MonoBehaviour
    {
    
    
        [SerializeField] private RectTransform off;
        [SerializeField] private RectTransform on;
        //动画时长
        [SerializeField, Range(0.1f, 0.3f)] private float duration = 0.2f;

        private Toggle toggle;
        private Coroutine coroutine;
        private Vector3 offPosition;
        private Vector3 onPosition;

        private void Awake()
        {
    
    
            toggle = GetComponent<Toggle>();
            toggle.onValueChanged.AddListener(OnValueChanged);
        }

        private void Start()
        {
    
    
            offPosition = off.position;
            onPosition = on.position;
            off.gameObject.SetActive(!toggle.isOn);
            on.gameObject.SetActive(toggle.isOn);
        }

        private void OnValueChanged(bool isOn)
        {
    
    
            if (coroutine != null)
                StopCoroutine(coroutine);

            coroutine = isOn ? StartCoroutine(Switch2OnCoroutine()) : StartCoroutine(Switch2OffCoroutine());
        }

        private IEnumerator Switch2OnCoroutine()
        {
    
    
            off.gameObject.SetActive(false);
            on.gameObject.SetActive(true);

            float beginTime = Time.time;    
            for (; Time.time - beginTime <= duration; )
            {
    
    
                float t = (Time.time - beginTime) / duration;
                on.position = Vector3.Lerp(offPosition, onPosition, t);
                yield return null;
            }
            on.position = onPosition;
            coroutine = null;
        }

        private IEnumerator Switch2OffCoroutine()
        {
    
    
            on.gameObject.SetActive(false);
            off.gameObject.SetActive(true);

            float beginTime = Time.time;
            for (; Time.time - beginTime <= duration;)
            {
    
    
                float t = (Time.time - beginTime) / duration;
                off.position = Vector3.Lerp(onPosition, offPosition, t);
                yield return null;
            }
            off.position = offPosition;
            coroutine = null;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42139931/article/details/129100153