158 lines
5.9 KiB
C#
158 lines
5.9 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using DG.Tweening;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 可视化UI动画组件:以步骤列表驱动DOTween播放
|
|||
|
|
/// 支持 位移/缩放/旋转/透明度 四类动画,正向/反向/停止
|
|||
|
|
/// 配合 UIAnimatorInspector 可在 Inspector 中可视化编排并预览
|
|||
|
|
/// </summary>
|
|||
|
|
public class UIAnimator : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
public enum UIAnimationType
|
|||
|
|
{
|
|||
|
|
Move, // 位移(相对偏移)
|
|||
|
|
Scale, // 缩放(目标值)
|
|||
|
|
Rotate, // 旋转(目标角度,绕Z轴)
|
|||
|
|
Alpha // 透明度(目标值,需CanvasGroup)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Serializable]
|
|||
|
|
public class UIAnimationStep
|
|||
|
|
{
|
|||
|
|
[Tooltip("动画类型")] public UIAnimationType type = UIAnimationType.Move;
|
|||
|
|
[Tooltip("步骤开始前的延迟(秒)")] public float delay;
|
|||
|
|
[Tooltip("动画时长(秒)")] public float duration = 0.5f;
|
|||
|
|
[Tooltip("缓动曲线")] public Ease ease = Ease.OutQuad;
|
|||
|
|
[Tooltip("位移偏移量(相对当前位置)")] public Vector3 moveOffset = Vector3.zero;
|
|||
|
|
[Tooltip("缩放目标值")] public Vector3 targetScale = Vector3.one;
|
|||
|
|
[Tooltip("旋转目标角度(绕Z轴)")] public float targetRotation;
|
|||
|
|
[Tooltip("透明度目标值(0-1)")] public float targetAlpha = 1f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Tooltip("动画步骤列表")] public List<UIAnimationStep> steps = new List<UIAnimationStep>();
|
|||
|
|
[Tooltip("启动时自动播放")] public bool playOnAwake;
|
|||
|
|
[Tooltip("无CanvasGroup时自动添加(Alpha动画需要)")] public bool autoAddCanvasGroup = true;
|
|||
|
|
|
|||
|
|
private RectTransform rectTransform;
|
|||
|
|
private CanvasGroup canvasGroup;
|
|||
|
|
private Sequence sequence;
|
|||
|
|
|
|||
|
|
// 初始状态缓存(反向播放与编辑器预览需要)
|
|||
|
|
public Vector3 InitialAnchoredPosition3D { get; private set; }
|
|||
|
|
public Vector3 InitialLocalScale { get; private set; }
|
|||
|
|
public float InitialRotationZ { get; private set; }
|
|||
|
|
public float InitialAlpha { get; private set; }
|
|||
|
|
|
|||
|
|
public RectTransform RectTransform => rectTransform;
|
|||
|
|
public CanvasGroup CanvasGroup => canvasGroup;
|
|||
|
|
|
|||
|
|
/// <summary>动画总时长(所有步骤的 延迟+时长 之和)</summary>
|
|||
|
|
public float TotalDuration
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
float total = 0;
|
|||
|
|
if (steps != null)
|
|||
|
|
foreach (var step in steps) total += step.delay + step.duration;
|
|||
|
|
return total;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Awake()
|
|||
|
|
{
|
|||
|
|
rectTransform = GetComponent<RectTransform>();
|
|||
|
|
canvasGroup = GetComponent<CanvasGroup>();
|
|||
|
|
if (canvasGroup == null && autoAddCanvasGroup)
|
|||
|
|
canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
|||
|
|
SaveInitialState();
|
|||
|
|
if (playOnAwake) Play();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>记录当前状态为初始状态(反向播放/预览的基准)</summary>
|
|||
|
|
public void SaveInitialState()
|
|||
|
|
{
|
|||
|
|
if (rectTransform == null) rectTransform = GetComponent<RectTransform>();
|
|||
|
|
if (canvasGroup == null) canvasGroup = GetComponent<CanvasGroup>();
|
|||
|
|
if (rectTransform == null) return;
|
|||
|
|
InitialAnchoredPosition3D = rectTransform.anchoredPosition3D;
|
|||
|
|
InitialLocalScale = rectTransform.localScale;
|
|||
|
|
InitialRotationZ = rectTransform.localEulerAngles.z;
|
|||
|
|
InitialAlpha = canvasGroup != null ? canvasGroup.alpha : 1f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>正向播放</summary>
|
|||
|
|
public void Play() => PlaySequence(false);
|
|||
|
|
|
|||
|
|
/// <summary>反向播放(从当前状态回到初始状态)</summary>
|
|||
|
|
public void PlayReverse() => PlaySequence(true);
|
|||
|
|
|
|||
|
|
/// <summary>停止并保持当前状态</summary>
|
|||
|
|
public void Stop()
|
|||
|
|
{
|
|||
|
|
sequence?.Kill();
|
|||
|
|
sequence = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void PlaySequence(bool reverse)
|
|||
|
|
{
|
|||
|
|
sequence?.Kill();
|
|||
|
|
sequence = reverse ? CreateReverseSequence() : CreateForwardSequence();
|
|||
|
|
if (sequence == null) return;
|
|||
|
|
sequence.Play();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private Sequence CreateForwardSequence()
|
|||
|
|
{
|
|||
|
|
if (rectTransform == null || steps == null || steps.Count == 0) return null;
|
|||
|
|
Sequence seq = DOTween.Sequence();
|
|||
|
|
foreach (var step in steps)
|
|||
|
|
{
|
|||
|
|
Tween t = CreateStepTween(step, false);
|
|||
|
|
if (t == null) continue;
|
|||
|
|
if (step.delay > 0) t.SetDelay(step.delay);
|
|||
|
|
seq.Append(t);
|
|||
|
|
}
|
|||
|
|
return seq;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private Sequence CreateReverseSequence()
|
|||
|
|
{
|
|||
|
|
if (rectTransform == null || steps == null || steps.Count == 0) return null;
|
|||
|
|
Sequence seq = DOTween.Sequence();
|
|||
|
|
for (int i = steps.Count - 1; i >= 0; i--)
|
|||
|
|
{
|
|||
|
|
Tween t = CreateStepTween(steps[i], true);
|
|||
|
|
if (t == null) continue;
|
|||
|
|
if (steps[i].delay > 0) t.SetDelay(steps[i].delay);
|
|||
|
|
seq.Append(t);
|
|||
|
|
}
|
|||
|
|
return seq;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private Tween CreateStepTween(UIAnimationStep step, bool reverse)
|
|||
|
|
{
|
|||
|
|
switch (step.type)
|
|||
|
|
{
|
|||
|
|
case UIAnimationType.Move:
|
|||
|
|
// 反向时位移取负偏移(回到初始位置)
|
|||
|
|
return rectTransform.DOAnchorPos3D(reverse ? -step.moveOffset : step.moveOffset, step.duration)
|
|||
|
|
.SetRelative().SetEase(step.ease);
|
|||
|
|
case UIAnimationType.Scale:
|
|||
|
|
return rectTransform.DOScale(reverse ? InitialLocalScale : step.targetScale, step.duration).SetEase(step.ease);
|
|||
|
|
case UIAnimationType.Rotate:
|
|||
|
|
return rectTransform.DOLocalRotate(
|
|||
|
|
new Vector3(0, 0, reverse ? InitialRotationZ : step.targetRotation), step.duration).SetEase(step.ease);
|
|||
|
|
case UIAnimationType.Alpha:
|
|||
|
|
if (canvasGroup == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("[UIAnimator] Alpha动画需要CanvasGroup,请手动添加或开启autoAddCanvasGroup", this);
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
return canvasGroup.DOFade(reverse ? InitialAlpha : step.targetAlpha, step.duration).SetEase(step.ease);
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|