using System; using PrimeTween; using UnityEngine.UIElements; namespace DanieleMarotta.RiversongCodeShowcase { public class UIVisibilityAnimation { private VisualElement _element; private Action _onCompleted; private Sequence _visibilityAnimation; public UIVisibilityAnimation(VisualElement element, Action onCompleted) { _element = element; _onCompleted = onCompleted; IsOpen = element.resolvedStyle.display != DisplayStyle.None; TargetIsOpen = IsOpen; ApplyCommittedState(IsOpen); } public bool IsOpen { get; private set; } public bool TargetIsOpen { get; private set; } public bool IsAnimating => _visibilityAnimation.isAlive; public void Show(bool show, bool animate = false) { TargetIsOpen = show; if (IsAnimating) return; if (IsOpen == TargetIsOpen) return; if (!animate) { ApplyCommittedState(TargetIsOpen); IsOpen = TargetIsOpen; _onCompleted?.Invoke(IsOpen); return; } TryAdvance(); } private void TryAdvance() { if (IsAnimating) return; if (IsOpen == TargetIsOpen) return; if (TargetIsOpen) PlayOpenAnimation(); else PlayCloseAnimation(); } private void PlayOpenAnimation() { _element.style.display = DisplayStyle.Flex; _visibilityAnimation = PlayShowTween(_element).OnComplete(() => CompleteTransition(true)); } private void PlayCloseAnimation() { _element.style.display = DisplayStyle.Flex; _visibilityAnimation = PlayHideTween(_element).OnComplete(() => CompleteTransition(false)); } private void CompleteTransition(bool isOpen) { _visibilityAnimation = default; ApplyCommittedState(isOpen); IsOpen = isOpen; _onCompleted?.Invoke(IsOpen); TryAdvance(); } private void ApplyCommittedState(bool isOpen) { _element.style.display = isOpen ? DisplayStyle.Flex : DisplayStyle.None; _element.style.opacity = isOpen ? 1 : 0; if (isOpen) _element.style.scale = StyleKeyword.Null; else _element.SetScale(0.8f); } public static Sequence PlayShowTween(VisualElement element, float duration = 0.3f) { element.style.opacity = 0; element.SetScale(0.8f); return Sequence.Create(useUnscaledTime: true) .Group(Tween.Custom(0.8f, 1, duration, element.SetScale, Ease.OutQuad)) .Group(Tween.Custom(0, 1, duration, value => element.style.opacity = value, Ease.OutQuad)); } public static Sequence PlayHideTween(VisualElement element, float duration = 0.2f) { element.style.opacity = 1; element.SetScale(1); return Sequence.Create(useUnscaledTime: true) .Group(Tween.Custom(1, 0.8f, duration, value => element.SetScale(value), Ease.OutQuad)) .Group(Tween.Custom(1, 0, duration, value => element.style.opacity = value, Ease.OutQuad)); } } }