UI系统
This commit is contained in:
@@ -36,6 +36,23 @@ namespace BaseGames.UI
|
||||
[Tooltip("打开时是否自动把焦点设到首项。")]
|
||||
[SerializeField] protected bool _selectFirstOnEnable = true;
|
||||
|
||||
[Header("导航栈")]
|
||||
[Tooltip("被压栈时,正下方面板的处理方式:Replace 停用下层(整屏切换);Modal 保留下层可见但屏蔽其交互(对话框)。")]
|
||||
[SerializeField] protected PushMode _defaultMode = PushMode.Replace;
|
||||
|
||||
[Tooltip("是否允许 ESC / 手柄 B 取消本面板(栈顶时)。确认破坏性操作的根面板可关闭。")]
|
||||
[SerializeField] protected bool _canCancel = true;
|
||||
|
||||
/// <summary>被压栈方式(<see cref="IUINavigator.Push"/> 未显式指定 mode 时采用)。</summary>
|
||||
public PushMode DefaultMode => _defaultMode;
|
||||
|
||||
/// <summary>栈顶时 ESC / 手柄 B 是否可取消本面板。</summary>
|
||||
public bool CanCancel => _canCancel;
|
||||
|
||||
/// <summary>键盘 / 手柄默认焦点项(<see cref="_firstSelected"/> 优先,否则 <see cref="ResolveFirstSelected"/>)。供导航器出/入栈聚焦。</summary>
|
||||
public GameObject FirstSelectableGO
|
||||
=> _firstSelected != null ? _firstSelected.gameObject : ResolveFirstSelected();
|
||||
|
||||
/// <summary>事件订阅容器,OnDisable 自动清理。子类订阅用 <c>channel.Subscribe(..).AddTo(_subs)</c>。</summary>
|
||||
protected readonly CompositeDisposable _subs = new();
|
||||
|
||||
@@ -44,6 +61,7 @@ namespace BaseGames.UI
|
||||
// ── 生命周期 ──────────────────────────────────────────────────────────
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (_canvasGroup == null) _canvasGroup = GetComponent<CanvasGroup>(); // 惰性解析(兼容运行时适配/未连线)
|
||||
OnPanelOpen();
|
||||
if (_canvasGroup != null && _fadeInDuration > 0f) PlayFadeIn();
|
||||
if (_selectFirstOnEnable) FocusFirst();
|
||||
@@ -62,9 +80,29 @@ namespace BaseGames.UI
|
||||
/// <summary>面板关闭时调用(OnDisable,_subs 已清理之后)。子类在此释放非 _subs 资源。</summary>
|
||||
protected virtual void OnPanelClose() { }
|
||||
|
||||
// ── 导航栈交互屏蔽 ────────────────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// 切换本面板"是否参与交互/导航"。导航器把模态对话框压在本面板之上时,
|
||||
/// 以此屏蔽本面板(<see cref="CanvasGroup"/> interactable+blocksRaycasts=false)——
|
||||
/// 子控件 <c>Selectable.IsInteractable()</c> 随之为 false,自动退出 Unity 导航图,
|
||||
/// 杜绝方向键穿透到下层(无 CanvasGroup 时为空操作)。
|
||||
/// </summary>
|
||||
public void SetInteractableLayer(bool on)
|
||||
{
|
||||
if (_canvasGroup == null) return;
|
||||
_canvasGroup.interactable = on;
|
||||
_canvasGroup.blocksRaycasts = on;
|
||||
}
|
||||
|
||||
// ── 焦点 ──────────────────────────────────────────────────────────────
|
||||
/// <summary>关闭子面板、本面板恢复为栈顶时调用(<see cref="IUIManager.CloseTopPanel"/> 触发)。</summary>
|
||||
public virtual void OnFocusRestored() => FocusFirst();
|
||||
/// <summary>本面板重新成为栈顶(上层出栈)时调用:默认聚焦首项。</summary>
|
||||
public virtual void OnFocusGained() => FocusFirst();
|
||||
|
||||
/// <summary>本面板被上层压栈覆盖时调用(可选钩子,默认无操作)。</summary>
|
||||
public virtual void OnFocusLost() { }
|
||||
|
||||
/// <summary>兼容旧 <see cref="IFocusable"/> 路径:等价于 <see cref="OnFocusGained"/>。</summary>
|
||||
public virtual void OnFocusRestored() => OnFocusGained();
|
||||
|
||||
/// <summary>将 EventSystem 焦点设到首项(优先 <see cref="_firstSelected"/>,否则 <see cref="ResolveFirstSelected"/>)。</summary>
|
||||
protected void FocusFirst()
|
||||
|
||||
Reference in New Issue
Block a user