接口化UIAnimationTransition
This commit is contained in:
parent
c692b47a62
commit
9e42167e72
@ -56,6 +56,16 @@ namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
if (meta.State != UIState.CreatedUI) return;
|
||||
GameObject obj = await LoadUIResourcesAsync(meta.ResInfo, parent);
|
||||
if (meta.CancellationToken.IsCancellationRequested || meta.View == null || meta.State != UIState.CreatedUI)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ValidateAndBind(meta, obj, owner);
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,11 @@ namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
CreateMetaUI(metaInfo);
|
||||
await UIHolderFactory.CreateUIResourceAsync(metaInfo, UICacheLayer);
|
||||
if (metaInfo.View == null || metaInfo.State == UIState.Uninitialized || metaInfo.State == UIState.Destroyed)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
FinalizeShow(metaInfo, userDatas);
|
||||
await UpdateVisualState(metaInfo, metaInfo.CancellationToken);
|
||||
return metaInfo.View;
|
||||
@ -38,6 +43,11 @@ namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
CreateMetaUI(metaInfo);
|
||||
UIHolderFactory.CreateUIResourceSync(metaInfo, UICacheLayer);
|
||||
if (metaInfo.View == null || metaInfo.State == UIState.Uninitialized || metaInfo.State == UIState.Destroyed)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
FinalizeShow(metaInfo, userDatas);
|
||||
UpdateVisualState(metaInfo).Forget();
|
||||
return metaInfo.View;
|
||||
@ -45,13 +55,36 @@ namespace AlicizaX.UI.Runtime
|
||||
|
||||
private async UniTask CloseUIImpl(UIMetadata meta, bool force)
|
||||
{
|
||||
if (meta.State == UIState.Uninitialized || meta.State == UIState.CreatedUI)
|
||||
if (meta.State == UIState.Uninitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (meta.State == UIState.CreatedUI)
|
||||
{
|
||||
meta.CancelAsyncOperations();
|
||||
meta.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
if (meta.State == UIState.Loaded || meta.State == UIState.Initialized)
|
||||
{
|
||||
meta.CancelAsyncOperations();
|
||||
Pop(meta);
|
||||
SortWindowVisible(meta.MetaInfo.UILayer);
|
||||
SortWindowDepth(meta.MetaInfo.UILayer);
|
||||
meta.View.Visible = false;
|
||||
CacheWindow(meta, force);
|
||||
return;
|
||||
}
|
||||
|
||||
meta.CancelAsyncOperations();
|
||||
await meta.View.InternalClose();
|
||||
if (meta.State != UIState.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Pop(meta);
|
||||
SortWindowVisible(meta.MetaInfo.UILayer);
|
||||
SortWindowDepth(meta.MetaInfo.UILayer);
|
||||
@ -85,6 +118,8 @@ namespace AlicizaX.UI.Runtime
|
||||
case UIState.Loaded:
|
||||
Push(meta);
|
||||
break;
|
||||
case UIState.Opening:
|
||||
case UIState.Closing:
|
||||
case UIState.Opened:
|
||||
MoveToTop(meta);
|
||||
break;
|
||||
@ -186,7 +221,7 @@ namespace AlicizaX.UI.Runtime
|
||||
for (int i = count - 1; i >= 0; i--)
|
||||
{
|
||||
var meta = list[i];
|
||||
if (meta.MetaInfo.FullScreen && meta.State == UIState.Opened)
|
||||
if (meta.MetaInfo.FullScreen && UIStateMachine.IsDisplayActive(meta.State))
|
||||
{
|
||||
fullscreenIdx = i;
|
||||
break;
|
||||
|
||||
14
Runtime/UI/Other/IUITransitionPlayer.cs
Normal file
14
Runtime/UI/Other/IUITransitionPlayer.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
public interface IUITransitionPlayer
|
||||
{
|
||||
UniTask PlayOpenAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
UniTask PlayCloseAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
void Stop();
|
||||
}
|
||||
}
|
||||
11
Runtime/UI/Other/IUITransitionPlayer.cs.meta
Normal file
11
Runtime/UI/Other/IUITransitionPlayer.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b746e052b3511314993f07f959473956
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
74
Runtime/UI/Other/UIAnimationFlowTransition.cs
Normal file
74
Runtime/UI/Other/UIAnimationFlowTransition.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.UI.Runtime
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public sealed class UIAnimationFlowTransition : MonoBehaviour, IUITransitionPlayer
|
||||
{
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
[SerializeField] private AnimationFlow.Runtime.AnimationFlow animationFlow;
|
||||
[SerializeField] private string openClip = "Open";
|
||||
[SerializeField] private string closeClip = "Close";
|
||||
#endif
|
||||
|
||||
public UniTask PlayOpenAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
return PlayAsync(openClip, cancellationToken);
|
||||
#else
|
||||
return UniTask.CompletedTask;
|
||||
#endif
|
||||
}
|
||||
|
||||
public UniTask PlayCloseAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
return PlayAsync(closeClip, cancellationToken);
|
||||
#else
|
||||
return UniTask.CompletedTask;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
ResolveAnimationFlow()?.Stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
private UniTask PlayAsync(string clipName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested || string.IsNullOrWhiteSpace(clipName))
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
AnimationFlow.Runtime.AnimationFlow flow = ResolveAnimationFlow();
|
||||
return flow == null ? UniTask.CompletedTask : flow.PlayAsync(clipName);
|
||||
}
|
||||
|
||||
private AnimationFlow.Runtime.AnimationFlow ResolveAnimationFlow()
|
||||
{
|
||||
if (animationFlow == null)
|
||||
{
|
||||
animationFlow = GetComponent<AnimationFlow.Runtime.AnimationFlow>();
|
||||
}
|
||||
|
||||
return animationFlow;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
if (animationFlow == null)
|
||||
{
|
||||
animationFlow = GetComponent<AnimationFlow.Runtime.AnimationFlow>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Runtime/UI/Other/UIAnimationFlowTransition.cs.meta
Normal file
11
Runtime/UI/Other/UIAnimationFlowTransition.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ad79303854072f4798edbea92187a26
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -22,6 +22,7 @@ namespace AlicizaX.UI.Runtime
|
||||
internal Canvas _canvas;
|
||||
|
||||
internal GraphicRaycaster _raycaster;
|
||||
private int _lifecycleVersion;
|
||||
|
||||
internal UIState _state = UIState.Uninitialized;
|
||||
internal UIState State => _state;
|
||||
@ -217,31 +218,67 @@ namespace AlicizaX.UI.Runtime
|
||||
|
||||
internal async UniTask InternalOpen(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_state == UIState.Opened)
|
||||
return; // Already open
|
||||
if (_state == UIState.Opened || _state == UIState.Opening)
|
||||
return;
|
||||
|
||||
if (!UIStateMachine.ValidateTransition(GetType().Name, _state, UIState.Opened))
|
||||
if (!UIStateMachine.ValidateTransition(GetType().Name, _state, UIState.Opening))
|
||||
return;
|
||||
|
||||
int lifecycleVersion = BeginLifecycleTransition();
|
||||
_state = UIState.Opening;
|
||||
Visible = true;
|
||||
Holder.OnWindowBeforeShowEvent?.Invoke();
|
||||
try
|
||||
{
|
||||
await OnOpenAsync(cancellationToken);
|
||||
if (!IsCurrentLifecycleTransition(lifecycleVersion, UIState.Opening))
|
||||
return;
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await Holder.PlayOpenTransitionAsync(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsCurrentLifecycleTransition(lifecycleVersion, UIState.Opening))
|
||||
return;
|
||||
|
||||
_state = UIState.Opened;
|
||||
Visible = true;
|
||||
Holder.OnWindowBeforeShowEvent?.Invoke();
|
||||
await OnOpenAsync(cancellationToken);
|
||||
Holder.OnWindowAfterShowEvent?.Invoke();
|
||||
}
|
||||
|
||||
internal async UniTask InternalClose(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_state != UIState.Opened)
|
||||
if (_state == UIState.Closed || _state == UIState.Closing)
|
||||
return;
|
||||
|
||||
if (!UIStateMachine.ValidateTransition(GetType().Name, _state, UIState.Closed))
|
||||
if (!UIStateMachine.ValidateTransition(GetType().Name, _state, UIState.Closing))
|
||||
return;
|
||||
|
||||
int lifecycleVersion = BeginLifecycleTransition();
|
||||
_state = UIState.Closing;
|
||||
Holder.OnWindowBeforeClosedEvent?.Invoke();
|
||||
try
|
||||
{
|
||||
await OnCloseAsync(cancellationToken);
|
||||
_state = UIState.Closed;
|
||||
if (!IsCurrentLifecycleTransition(lifecycleVersion, UIState.Closing))
|
||||
return;
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await Holder.PlayCloseTransitionAsync(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsCurrentLifecycleTransition(lifecycleVersion, UIState.Closing))
|
||||
return;
|
||||
|
||||
Visible = false;
|
||||
_state = UIState.Closed;
|
||||
Holder.OnWindowAfterClosedEvent?.Invoke();
|
||||
}
|
||||
|
||||
@ -257,8 +294,9 @@ namespace AlicizaX.UI.Runtime
|
||||
if (!UIStateMachine.ValidateTransition(GetType().Name, _state, UIState.Destroying))
|
||||
return;
|
||||
|
||||
InterruptLifecycleTransition();
|
||||
_state = UIState.Destroying;
|
||||
Holder.OnWindowDestroyEvent?.Invoke();
|
||||
Holder?.OnWindowDestroyEvent?.Invoke();
|
||||
await DestroyAllChildren();
|
||||
OnDestroy();
|
||||
ReleaseEventListenerProxy();
|
||||
@ -271,6 +309,23 @@ namespace AlicizaX.UI.Runtime
|
||||
this._userDatas = userDatas;
|
||||
}
|
||||
|
||||
private int BeginLifecycleTransition()
|
||||
{
|
||||
InterruptLifecycleTransition();
|
||||
return _lifecycleVersion;
|
||||
}
|
||||
|
||||
private void InterruptLifecycleTransition()
|
||||
{
|
||||
_lifecycleVersion++;
|
||||
Holder?.StopTransition();
|
||||
}
|
||||
|
||||
private bool IsCurrentLifecycleTransition(int lifecycleVersion, UIState state)
|
||||
{
|
||||
return lifecycleVersion == _lifecycleVersion && _state == state;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
@ -15,27 +16,14 @@ namespace AlicizaX.UI.Runtime
|
||||
public Action OnWindowDestroyEvent;
|
||||
|
||||
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
public async UniTask PlayAnimtion(string name)
|
||||
{
|
||||
if (AnimationFlow == null)
|
||||
{
|
||||
AnimationFlow = transform.GetComponent<AnimationFlow.Runtime.AnimationFlow>();
|
||||
}
|
||||
|
||||
await AnimationFlow.PlayAsync(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
private GameObject _target;
|
||||
private IUITransitionPlayer _transitionPlayer;
|
||||
|
||||
/// <summary>
|
||||
/// UI实例资源对象。
|
||||
/// </summary>
|
||||
public GameObject Target => _target ??= gameObject;
|
||||
|
||||
|
||||
private RectTransform _rectTransform;
|
||||
|
||||
/// <summary>
|
||||
@ -53,30 +41,68 @@ namespace AlicizaX.UI.Runtime
|
||||
internal set { _target.SetActive(value); }
|
||||
}
|
||||
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
private AnimationFlow.Runtime.AnimationFlow AnimationFlow;
|
||||
#endif
|
||||
|
||||
|
||||
public virtual void Awake()
|
||||
{
|
||||
_target = gameObject;
|
||||
#if ALICIZAX_UI_ANIMATION_SUPPORT
|
||||
AnimationFlow = GetComponent<AnimationFlow.Runtime.AnimationFlow>();
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool _isAlive = true;
|
||||
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return this != null && _isAlive;
|
||||
}
|
||||
|
||||
internal UniTask PlayOpenTransitionAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return TryGetTransitionPlayer(out var transitionPlayer)
|
||||
? transitionPlayer.PlayOpenAsync(cancellationToken)
|
||||
: UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
internal UniTask PlayCloseTransitionAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return TryGetTransitionPlayer(out var transitionPlayer)
|
||||
? transitionPlayer.PlayCloseAsync(cancellationToken)
|
||||
: UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
internal void StopTransition()
|
||||
{
|
||||
if (TryGetTransitionPlayer(out var transitionPlayer))
|
||||
{
|
||||
transitionPlayer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetTransitionPlayer(out IUITransitionPlayer transitionPlayer)
|
||||
{
|
||||
if (_transitionPlayer != null)
|
||||
{
|
||||
transitionPlayer = _transitionPlayer;
|
||||
return true;
|
||||
}
|
||||
|
||||
MonoBehaviour[] behaviours = GetComponents<MonoBehaviour>();
|
||||
for (int i = 0; i < behaviours.Length; i++)
|
||||
{
|
||||
if (behaviours[i] is IUITransitionPlayer player)
|
||||
{
|
||||
_transitionPlayer = player;
|
||||
transitionPlayer = player;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
transitionPlayer = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_isAlive = false;
|
||||
_transitionPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,9 @@
|
||||
CreatedUI,
|
||||
Loaded,
|
||||
Initialized,
|
||||
Opening,
|
||||
Opened,
|
||||
Closing,
|
||||
Closed,
|
||||
Destroying,
|
||||
Destroyed,
|
||||
|
||||
@ -9,11 +9,13 @@ namespace AlicizaX.UI.Runtime
|
||||
private static readonly Dictionary<UIState, HashSet<UIState>> _validTransitions = new()
|
||||
{
|
||||
[UIState.Uninitialized] = new() { UIState.CreatedUI },
|
||||
[UIState.CreatedUI] = new() { UIState.Loaded },
|
||||
[UIState.Loaded] = new() { UIState.Initialized },
|
||||
[UIState.Initialized] = new() { UIState.Opened },
|
||||
[UIState.Opened] = new() { UIState.Closed, UIState.Destroying },
|
||||
[UIState.Closed] = new() { UIState.Opened, UIState.Destroying },
|
||||
[UIState.CreatedUI] = new() { UIState.Loaded, UIState.Destroying },
|
||||
[UIState.Loaded] = new() { UIState.Initialized, UIState.Destroying },
|
||||
[UIState.Initialized] = new() { UIState.Opening, UIState.Destroying },
|
||||
[UIState.Opening] = new() { UIState.Opened, UIState.Closing, UIState.Destroying },
|
||||
[UIState.Opened] = new() { UIState.Closing, UIState.Destroying },
|
||||
[UIState.Closing] = new() { UIState.Opening, UIState.Closed, UIState.Destroying },
|
||||
[UIState.Closed] = new() { UIState.Opening, UIState.Destroying },
|
||||
[UIState.Destroying] = new() { UIState.Destroyed },
|
||||
[UIState.Destroyed] = new() { }
|
||||
};
|
||||
@ -48,12 +50,19 @@ namespace AlicizaX.UI.Runtime
|
||||
UIState.CreatedUI => "UI logic created, awaiting resource load",
|
||||
UIState.Loaded => "Resources loaded, awaiting initialization",
|
||||
UIState.Initialized => "Initialized, ready to open",
|
||||
UIState.Opening => "Opening transition is running",
|
||||
UIState.Opened => "Currently visible and active",
|
||||
UIState.Closing => "Closing transition is running",
|
||||
UIState.Closed => "Hidden but cached",
|
||||
UIState.Destroying => "Being destroyed",
|
||||
UIState.Destroyed => "Fully destroyed",
|
||||
_ => "Unknown state"
|
||||
};
|
||||
}
|
||||
|
||||
public static bool IsDisplayActive(UIState state)
|
||||
{
|
||||
return state == UIState.Opening || state == UIState.Opened || state == UIState.Closing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user