跳到内容
CrossFly 是 100% 开源在 GitHub 关注我们
CrossFlyCrossFly
开始使用

本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。

如何在 controller 中集中管理导航

目的。 将 new X().show() 和 hide() 散布在各个屏幕中,会使 UI 与导航图耦合。一个 controller 集中管理 push/pop,提供一个用于日志/守卫的统一入口,并支持“关闭直到根屏幕”。它仅仅编排 EventsProcessor 的真实栈。

使用的 API

  • Window.show() / Window.hide() — 栈上的 push/pop(controller 只是委托给它们)。
  • EventsProcessor.topWindow() — 静态方法,返回栈顶窗口(instance.windows.peek())。
  • EventsProcessor.instance.getLastWindow() — 实例方法;返回栈的真实顶部(如果为空则返回 null)。当需要检查栈中是否有内容而不抛出异常时使用。

在 EventsProcessor 的源码中确认的名称:topWindow()(静态)和 getLastWindow()(实例)。topWindow() 执行 windows.peek(),如果栈为空则抛出异常;getLastWindow() 在这种情况下返回 null——防御性检查时优先使用后者。

完整示例(复制、粘贴并运行)

package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** 可执行主屏:使用 Nav 控制器压入/弹出屏幕。 */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(new Label("Tela raiz"));
      add(new Button("Abrir detalhe").onAction(e -> Nav.push(new OutraTela())));  // 通过控制器 push
   }
}

/** 栈内屏幕:通过控制器关闭(pop)。 */
class OutraTela extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(new Label("Detalhe"));
      add(new Button("Voltar").onAction(e -> Nav.pop()));  // 通过控制器 pop
   }
}

/** 控制器:对 EventsProcessor 真实栈的薄封装。 */
final class Nav
{
   private Nav() {}

   /** push:入栈并显示。 */
   public static void push(Window w)
   {
      w.show();
   }

   /** pop:关闭栈顶窗口(若有)。 */
   public static void pop()
   {
      Window top = EventsProcessor.instance.getLastWindow();  // null 安全
      if (top != null)
         top.hide();
   }

   /** 当前栈顶窗口(可能为 null)。 */
   public static Window current()
   {
      return EventsProcessor.instance.getLastWindow();
   }
}

下面的片段只展示核心部分。要运行它,请将其放入上面的 MainWindow 骨架中。

最小片段

// 已在源码核对:EventsProcessor.topWindow()(静态)与 instance.getLastWindow()(栈空时返回 null)
public final class Nav
{
   private Nav() {}

   /** push:入栈并显示。 */
   public static void push(Window w)
   {
      w.show();
   }

   /** pop:关闭栈顶窗口(若有)。 */
   public static void pop()
   {
      Window top = EventsProcessor.instance.getLastWindow();  // null 安全
      if (top != null)
         top.hide();
   }

   /** 反复 pop 直到只剩 1 个窗口(根窗口)。 */
   public static void popToRoot()
   {
      Window top;
      // 只要栈中窗口多于一个,就消掉栈顶
      while ((top = EventsProcessor.instance.getLastWindow()) != null
             && top != EventsProcessor.topWindow()) { top.hide(); }
      // (若要"回到根",每次 hide() 弹出一个;请按你的应用调整停止条件)
   }

   /** 当前栈顶窗口(可能为 null)。 */
   public static Window current()
   {
      return EventsProcessor.instance.getLastWindow();
   }
}

// 在屏幕中的用法:
Nav.push(new DetalheTela());
// ...
Nav.pop();

最佳实践:

  • 不要重新实现栈:EventsProcessor 已经是唯一的事实来源。controller 是 show()/hide() 之上的一个薄门面。
  • 导航守卫(例如:“有未保存的更改吗?”)在这里很自然:在 pop() 之前检查,如有必要,弹出一个确认 Alert。
  • 当栈可能为空时要小心 topWindow()——它执行 peek() 并会抛出异常。对于防御性代码请使用 getLastWindow()。

深入了解

这个页面有帮助吗?