改动与优化
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
public static class UI_PanelExitUtility
|
||||
{
|
||||
private const float FallbackExitDuration = 0.16f;
|
||||
private const float FallbackExitScale = 0.96f;
|
||||
private static readonly HashSet<GameObject> ExitingPanels = new HashSet<GameObject>();
|
||||
|
||||
public static bool PlayExitThen(GameObject panel, Action onComplete)
|
||||
{
|
||||
if (panel == null || !panel.activeInHierarchy)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ExitingPanels.Contains(panel))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ExitingPanels.Add(panel);
|
||||
bool completed = false;
|
||||
Action safeComplete = () =>
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
completed = true;
|
||||
ExitingPanels.Remove(panel);
|
||||
onComplete?.Invoke();
|
||||
};
|
||||
|
||||
DOVirtual.DelayedCall(2.5f, () => safeComplete(), true);
|
||||
|
||||
UI_SettingsPanelEnterAnim settingsAnim = panel.GetComponent<UI_SettingsPanelEnterAnim>();
|
||||
if (settingsAnim != null && settingsAnim.enabled)
|
||||
{
|
||||
settingsAnim.PlayExitThen(safeComplete);
|
||||
return true;
|
||||
}
|
||||
|
||||
UI_PanelPopupTween popupTween = panel.GetComponent<UI_PanelPopupTween>();
|
||||
if (popupTween != null && popupTween.enabled)
|
||||
{
|
||||
popupTween.PlayExitThen(safeComplete);
|
||||
return true;
|
||||
}
|
||||
|
||||
return PlayFallbackExitThen(panel, safeComplete);
|
||||
}
|
||||
|
||||
private static bool PlayFallbackExitThen(GameObject panel, Action onComplete)
|
||||
{
|
||||
RectTransform rect = panel != null ? panel.transform as RectTransform : null;
|
||||
CanvasGroup group = panel != null ? panel.GetComponent<CanvasGroup>() : null;
|
||||
|
||||
if (rect == null && group == null)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
group = panel.AddComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
Vector3 baseScale = rect != null ? rect.localScale : Vector3.one;
|
||||
float baseAlpha = group.alpha;
|
||||
float duration = Mathf.Max(0.01f, FallbackExitDuration);
|
||||
bool canScale = rect == null || !UI_OrderedEntryAnimator.IsLayoutSensitive(rect);
|
||||
|
||||
if (rect != null)
|
||||
{
|
||||
rect.DOKill();
|
||||
}
|
||||
|
||||
group.DOKill();
|
||||
group.interactable = false;
|
||||
group.blocksRaycasts = false;
|
||||
|
||||
Sequence seq = DOTween.Sequence().SetUpdate(true);
|
||||
if (rect != null && canScale)
|
||||
{
|
||||
seq.Join(rect.DOScale(baseScale * FallbackExitScale, duration).SetEase(Ease.InCubic));
|
||||
}
|
||||
seq.Join(group.DOFade(0f, duration).SetEase(Ease.InCubic));
|
||||
bool restored = false;
|
||||
Action restore = () =>
|
||||
{
|
||||
if (restored)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
restored = true;
|
||||
if (rect != null && canScale)
|
||||
{
|
||||
rect.localScale = baseScale;
|
||||
}
|
||||
|
||||
if (group != null)
|
||||
{
|
||||
group.alpha = baseAlpha;
|
||||
group.interactable = true;
|
||||
group.blocksRaycasts = true;
|
||||
}
|
||||
};
|
||||
|
||||
seq.OnComplete(() =>
|
||||
{
|
||||
restore();
|
||||
onComplete?.Invoke();
|
||||
});
|
||||
seq.OnKill(() => restore());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f3638fba040b34429d7d54c473508b5
|
||||
@@ -0,0 +1,199 @@
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class UI_PanelPopupTween : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private RectTransform moveTarget;
|
||||
[SerializeField] private CanvasGroup fadeTarget;
|
||||
[SerializeField] private bool playOnEnable = true;
|
||||
[SerializeField] private float enterDuration = 0.2f;
|
||||
[SerializeField] private float exitDuration = 0.16f;
|
||||
[SerializeField] private float fromOffsetY = 24f;
|
||||
[SerializeField] private float scaleFrom = 0.96f;
|
||||
[SerializeField] private Ease enterEase = Ease.OutCubic;
|
||||
[SerializeField] private Ease exitEase = Ease.InCubic;
|
||||
[SerializeField] private bool useUnscaledTime = true;
|
||||
|
||||
private Sequence enterSequence;
|
||||
private bool baseCached;
|
||||
private Vector2 basePos;
|
||||
private Vector3 baseScale;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
AutoWire();
|
||||
CacheBaseState();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (playOnEnable)
|
||||
{
|
||||
Play();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
KillTween();
|
||||
ResetToBase();
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
AutoWire();
|
||||
CacheBaseState();
|
||||
|
||||
if (moveTarget == null || fadeTarget == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
KillTween();
|
||||
|
||||
Vector2 fromPos = basePos + new Vector2(0f, -Mathf.Abs(fromOffsetY));
|
||||
bool canAnimateTransform = !UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget);
|
||||
if (canAnimateTransform)
|
||||
{
|
||||
moveTarget.anchoredPosition = fromPos;
|
||||
moveTarget.localScale = baseScale * Mathf.Max(0.01f, scaleFrom);
|
||||
}
|
||||
fadeTarget.alpha = 0f;
|
||||
fadeTarget.interactable = false;
|
||||
fadeTarget.blocksRaycasts = false;
|
||||
|
||||
float duration = Mathf.Max(0.01f, enterDuration);
|
||||
enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
|
||||
if (canAnimateTransform)
|
||||
{
|
||||
enterSequence.Join(moveTarget.DOAnchorPos(basePos, duration).SetEase(enterEase));
|
||||
enterSequence.Join(moveTarget.DOScale(baseScale, duration).SetEase(enterEase));
|
||||
}
|
||||
enterSequence.Join(fadeTarget.DOFade(1f, duration).SetEase(Ease.OutCubic));
|
||||
enterSequence.OnComplete(() =>
|
||||
{
|
||||
fadeTarget.interactable = true;
|
||||
fadeTarget.blocksRaycasts = true;
|
||||
enterSequence = null;
|
||||
});
|
||||
enterSequence.OnKill(() =>
|
||||
{
|
||||
ResetToBase();
|
||||
enterSequence = null;
|
||||
});
|
||||
}
|
||||
|
||||
public void PlayExitThen(System.Action onComplete)
|
||||
{
|
||||
AutoWire();
|
||||
CacheBaseState();
|
||||
|
||||
if (moveTarget == null || fadeTarget == null)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
KillTween();
|
||||
|
||||
fadeTarget.interactable = false;
|
||||
fadeTarget.blocksRaycasts = false;
|
||||
|
||||
Vector2 targetPos = basePos + new Vector2(0f, -Mathf.Abs(fromOffsetY));
|
||||
Vector3 targetScale = baseScale * Mathf.Max(0.01f, scaleFrom);
|
||||
float duration = Mathf.Max(0.01f, exitDuration);
|
||||
bool canAnimateTransform = !UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget);
|
||||
|
||||
enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
|
||||
if (canAnimateTransform)
|
||||
{
|
||||
enterSequence.Join(moveTarget.DOAnchorPos(targetPos, duration).SetEase(exitEase));
|
||||
enterSequence.Join(moveTarget.DOScale(targetScale, duration).SetEase(exitEase));
|
||||
}
|
||||
enterSequence.Join(fadeTarget.DOFade(0f, duration).SetEase(Ease.InCubic));
|
||||
enterSequence.OnComplete(() =>
|
||||
{
|
||||
enterSequence = null;
|
||||
ResetToBase();
|
||||
onComplete?.Invoke();
|
||||
});
|
||||
enterSequence.OnKill(() =>
|
||||
{
|
||||
ResetToBase();
|
||||
enterSequence = null;
|
||||
});
|
||||
}
|
||||
|
||||
private void AutoWire()
|
||||
{
|
||||
if (moveTarget == null)
|
||||
{
|
||||
moveTarget = transform as RectTransform;
|
||||
if (moveTarget == null)
|
||||
{
|
||||
moveTarget = GetComponentInChildren<RectTransform>(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (fadeTarget == null)
|
||||
{
|
||||
fadeTarget = GetComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
if (fadeTarget == null)
|
||||
{
|
||||
fadeTarget = gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheBaseState()
|
||||
{
|
||||
if (moveTarget == null || baseCached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
basePos = moveTarget.anchoredPosition;
|
||||
baseScale = moveTarget.localScale;
|
||||
baseCached = true;
|
||||
}
|
||||
|
||||
private void ResetToBase()
|
||||
{
|
||||
if (moveTarget != null && baseCached)
|
||||
{
|
||||
if (!UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget))
|
||||
{
|
||||
moveTarget.anchoredPosition = basePos;
|
||||
moveTarget.localScale = baseScale;
|
||||
}
|
||||
}
|
||||
|
||||
if (fadeTarget != null)
|
||||
{
|
||||
fadeTarget.alpha = 1f;
|
||||
fadeTarget.interactable = true;
|
||||
fadeTarget.blocksRaycasts = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void KillTween()
|
||||
{
|
||||
if (enterSequence != null)
|
||||
{
|
||||
enterSequence.Kill();
|
||||
enterSequence = null;
|
||||
}
|
||||
|
||||
if (moveTarget != null)
|
||||
{
|
||||
moveTarget.DOKill();
|
||||
}
|
||||
|
||||
if (fadeTarget != null)
|
||||
{
|
||||
fadeTarget.DOKill();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 684368a613daac84599aaf0ef6b4c77a
|
||||
@@ -8,8 +8,10 @@ public class UI_SettingsPanelEnterAnim : MonoBehaviour
|
||||
[SerializeField] private CanvasGroup fadeTarget;
|
||||
[SerializeField] private bool playOnEnable = true;
|
||||
[SerializeField] private float enterDuration = 0.3f;
|
||||
[SerializeField] private float exitDuration = 0.18f;
|
||||
[SerializeField] private float fromOffsetY = 32f;
|
||||
[SerializeField] private Ease enterEase = Ease.OutCubic;
|
||||
[SerializeField] private Ease exitEase = Ease.InCubic;
|
||||
[SerializeField] private bool useUnscaledTime = true;
|
||||
|
||||
private Sequence enterSequence;
|
||||
@@ -44,13 +46,20 @@ public class UI_SettingsPanelEnterAnim : MonoBehaviour
|
||||
|
||||
KillTween();
|
||||
|
||||
moveTarget.anchoredPosition = basePos - new Vector2(0f, Mathf.Abs(fromOffsetY));
|
||||
bool canAnimateTransform = !UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget);
|
||||
if (canAnimateTransform)
|
||||
{
|
||||
moveTarget.anchoredPosition = basePos - new Vector2(0f, Mathf.Abs(fromOffsetY));
|
||||
}
|
||||
fadeTarget.alpha = 0f;
|
||||
fadeTarget.interactable = false;
|
||||
fadeTarget.blocksRaycasts = false;
|
||||
|
||||
enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
|
||||
enterSequence.Join(moveTarget.DOAnchorPos(basePos, Mathf.Max(0.01f, enterDuration)).SetEase(enterEase));
|
||||
if (canAnimateTransform)
|
||||
{
|
||||
enterSequence.Join(moveTarget.DOAnchorPos(basePos, Mathf.Max(0.01f, enterDuration)).SetEase(enterEase));
|
||||
}
|
||||
enterSequence.Join(fadeTarget.DOFade(1f, Mathf.Max(0.01f, enterDuration)).SetEase(Ease.OutCubic));
|
||||
enterSequence.OnComplete(() =>
|
||||
{
|
||||
@@ -58,6 +67,50 @@ public class UI_SettingsPanelEnterAnim : MonoBehaviour
|
||||
fadeTarget.blocksRaycasts = true;
|
||||
enterSequence = null;
|
||||
});
|
||||
enterSequence.OnKill(() =>
|
||||
{
|
||||
ResetToBase();
|
||||
enterSequence = null;
|
||||
});
|
||||
}
|
||||
|
||||
public void PlayExitThen(System.Action onComplete)
|
||||
{
|
||||
AutoWire();
|
||||
CacheBasePos();
|
||||
|
||||
if (moveTarget == null || fadeTarget == null)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
KillTween();
|
||||
|
||||
fadeTarget.interactable = false;
|
||||
fadeTarget.blocksRaycasts = false;
|
||||
|
||||
Vector2 targetPos = basePos - new Vector2(0f, Mathf.Abs(fromOffsetY));
|
||||
float duration = Mathf.Max(0.01f, exitDuration);
|
||||
bool canAnimateTransform = !UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget);
|
||||
|
||||
enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime);
|
||||
if (canAnimateTransform)
|
||||
{
|
||||
enterSequence.Join(moveTarget.DOAnchorPos(targetPos, duration).SetEase(exitEase));
|
||||
}
|
||||
enterSequence.Join(fadeTarget.DOFade(0f, duration).SetEase(Ease.InCubic));
|
||||
enterSequence.OnComplete(() =>
|
||||
{
|
||||
enterSequence = null;
|
||||
ResetToBase();
|
||||
onComplete?.Invoke();
|
||||
});
|
||||
enterSequence.OnKill(() =>
|
||||
{
|
||||
ResetToBase();
|
||||
enterSequence = null;
|
||||
});
|
||||
}
|
||||
|
||||
private void AutoWire()
|
||||
@@ -90,7 +143,10 @@ public class UI_SettingsPanelEnterAnim : MonoBehaviour
|
||||
private void ResetToBase()
|
||||
{
|
||||
if (moveTarget != null && basePosCached)
|
||||
moveTarget.anchoredPosition = basePos;
|
||||
{
|
||||
if (!UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget))
|
||||
moveTarget.anchoredPosition = basePos;
|
||||
}
|
||||
|
||||
if (fadeTarget != null)
|
||||
{
|
||||
|
||||
@@ -1027,13 +1027,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|
||||
settingsInstance.SetActive(true);
|
||||
EnsureSettingsLastSibling();
|
||||
RegisterManagedPanel(settingsInstance, () =>
|
||||
{
|
||||
if (settingsInstance != null)
|
||||
{
|
||||
settingsInstance.SetActive(false);
|
||||
}
|
||||
});
|
||||
RegisterManagedPanel(settingsInstance, CloseSettingsWithExitAnim);
|
||||
NotifyManagedPanelVisibilityChanged(true);
|
||||
return;
|
||||
}
|
||||
@@ -1043,23 +1037,41 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
settingsInstance.transform.SetParent(GetSettingsParentTransform(), false);
|
||||
EnsureSettingsLastSibling();
|
||||
|
||||
// Toggle active state
|
||||
bool active = settingsInstance.activeSelf;
|
||||
settingsInstance.SetActive(!active);
|
||||
if (active)
|
||||
{
|
||||
CloseSettingsWithExitAnim();
|
||||
return;
|
||||
}
|
||||
|
||||
settingsInstance.SetActive(true);
|
||||
if (settingsInstance.activeSelf)
|
||||
{
|
||||
EnsureSettingsLastSibling();
|
||||
RegisterManagedPanel(settingsInstance, () =>
|
||||
{
|
||||
if (settingsInstance != null)
|
||||
{
|
||||
settingsInstance.SetActive(false);
|
||||
}
|
||||
});
|
||||
RegisterManagedPanel(settingsInstance, CloseSettingsWithExitAnim);
|
||||
}
|
||||
NotifyManagedPanelVisibilityChanged(true);
|
||||
}
|
||||
|
||||
private void CloseSettingsWithExitAnim()
|
||||
{
|
||||
if (settingsInstance == null)
|
||||
{
|
||||
NotifyManagedPanelVisibilityChanged(true);
|
||||
return;
|
||||
}
|
||||
|
||||
UI_PanelExitUtility.PlayExitThen(settingsInstance, () =>
|
||||
{
|
||||
if (settingsInstance != null)
|
||||
{
|
||||
settingsInstance.SetActive(false);
|
||||
}
|
||||
|
||||
NotifyManagedPanelVisibilityChanged(true);
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsSettingsPanelVisible
|
||||
{
|
||||
get { return settingsInstance != null && settingsInstance.activeInHierarchy; }
|
||||
@@ -1201,8 +1213,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
return;
|
||||
}
|
||||
|
||||
instance.SetActive(false);
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
CloseManagedOverlayWithExitAnim(instance);
|
||||
}
|
||||
|
||||
private bool ToggleIfAlreadyOpen(ref GameObject instance)
|
||||
@@ -1217,8 +1228,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
instance.SetActive(false);
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
CloseManagedOverlayWithExitAnim(instance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1250,12 +1260,34 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
}
|
||||
|
||||
AttachManagedPanelVisibilityRelay(instance, false);
|
||||
EnsurePanelPopupTween(instance);
|
||||
TryAssignCanvasCamera(instance);
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
EnsureTopNavigationFront();
|
||||
return true;
|
||||
}
|
||||
|
||||
private UI_PanelPopupTween EnsurePanelPopupTween(GameObject instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (instance.GetComponent<UI_SettingsPanelEnterAnim>() != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
UI_PanelPopupTween popupTween = instance.GetComponent<UI_PanelPopupTween>();
|
||||
if (popupTween == null)
|
||||
{
|
||||
popupTween = instance.AddComponent<UI_PanelPopupTween>();
|
||||
}
|
||||
|
||||
return popupTween;
|
||||
}
|
||||
|
||||
private void EnsureSettingsLastSibling()
|
||||
{
|
||||
if (settingsInstance == null || GetSettingsParentTransform() == null)
|
||||
@@ -1296,8 +1328,25 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
private void CloseInstance(ref GameObject instance, GameObject keep)
|
||||
{
|
||||
if (instance == null || instance == keep) return;
|
||||
instance.SetActive(false);
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
CloseManagedOverlayWithExitAnim(instance);
|
||||
}
|
||||
|
||||
private void CloseManagedOverlayWithExitAnim(GameObject instance)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UI_PanelExitUtility.PlayExitThen(instance, () =>
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
instance.SetActive(false);
|
||||
}
|
||||
|
||||
BroadcastOverlayPanelsVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
private GameObject FindExistingInstance(GameObject prefab)
|
||||
|
||||
Reference in New Issue
Block a user