T3 Code 非官方中文翻译不是官方产品,也不是 T3 Tools 官方文档。源提交 d2c25950b4d9英文原文GitHub 源文件
Skip to content

移动端布局 ​

移动应用运行在手机、折叠屏、平板以及可调整大小的 iPad 窗口上。靠一条规则,这件事才仍然可控:下面每一层只做一个决定,而且没有一层去做另一层的决定。功能屏幕从不过问自己在哪个平台上,也不过问窗口有多宽。

宽窗口示意为叠放的五层:路由、工作区外壳、功能屏幕、设计系统、原生

一张紧凑的 Android 屏幕,同样是这五层

各层 ​

  1. 路由。 根堆栈就是布局状态:选中了什么、推入了什么、哪张工作表开着。旋转、折叠或调整大小时,同一个堆栈会以不同方式渲染。没有任何东西记住页面曾经在哪一列。每条路由用一个预设声明自己是什么(pageRoute、sheetRoute、modalRoute、immersiveRoute);预设负责停靠档位、圆角、顶栏外观和 Android 回退。参见移动端导航。

  2. 工作区外壳。 features/layout负责位置与宽度,宽度等级来自 layout.ts:

    • 展开:侧边栏、内容与检查器三列。
    • 中等(宽 600–720pt):侧边栏挨着列表,并浮在页面之上。
    • 紧凑(任一方向不足 600pt):侧边栏是根,页面以推入方式打开。
    • 检查器列放不下时,检查器是一张工作表。

    工作区的标签页、停靠栏和工具栏位于 features/layout/workspace。嵌在工作表或弹出层里的堆栈,以及在自身路由下渲染的屏幕,也来自这里。

  3. 功能屏幕。 屏幕按角色摆放内容。它绘制一个 AppBar(表单工作表则用 SheetHeader),渲染自己的页面,用 <Inspector> 声明检查器窗格,并用 showInspector() 请求显示它们。外壳决定采用列还是工作表。在这里按宽度或平台去选择路由、组件、顶栏选项或内边距,正是这套结构要防止的错误。

  4. 设计系统。 每个窗格、页面、工作表和模态框都有一个 AppBar,两个平台上的约定相同;工作表或模态框会传入 onClose。PaneContext告诉栏自己位于哪一列,于是栏加上该列的控件,例如侧边栏开关。内容与栏相接的位置来自 useBarInset。界面框架只在这里按平台分叉。

  5. 原生。 在 iOS 26 上,这些列是各自带一条导航栏的 UISplitViewController 列。在 Android 以及 iPadOS 18–25 上,外壳根据窗口和铰链度量,用 JS 画出同样的列。Android 从不显示原生堆栈顶栏;每一条栏都在组件树内绘制。

平台分叉位于第 1、2、4 层,以 .ios 和 .android 文件的形式存在。

陷阱 ​

  • iPadOS 18–25 运行的是 JS 列,而 iOS 的部署目标是 18。JS 列路径里看起来只针对 Android 的代码,在这些 iPad 上仍然会执行。
  • Android 会把 Home 渲染两次:一次在侧边栏列中,一次作为内容堆栈的根。侧边栏那一份永远不是处于焦点的路由,因此以焦点为门控的 hook(例如返回处理)还必须接受 usePaneRole() === "sidebar"。
  • 模态框和全屏页面呈现在列之上,渲染时没有窗格角色,因此没有列的界面框架。
  • 在 iOS 上,每个检查器窗格都是独立的原生屏幕,只有当前活动的那个被挂接。即使用透明度隐藏,窗格的原生栏、工具栏和滚动视图仍在窗口中,UIKit 会把它们画在可见窗格上面。
  • 从检查器工作表打开的路由必须等工作表关闭,这通过 InspectorSheetContext 完成。在正在关闭的工作表之上呈现,会在 iOS 上与其关闭发生竞态。

非官方译文 · 源提交 d2c25950b4d9 · 不代表 T3 Tools