DirectSurface UIDirectSurface UI
开始使用
组件/布局原语

布局原语 / COMPONENT

UniformGrid

DirectSurface UI 使用约束传递模型:父节点向子节点传递 BoxConstraints,子节点在约束内计算 size,父节点再为子节点设置 offset。业务代码应使用布局组件表达结构,不要在 performPaint() 中手工计算页面坐标。

文档 READY示例 1
PUBLIC APIRenderUniformGrid

FUNCTION EXPLORER

可运行示例与完整源码。

这里始终保留组件的主运行入口;文档中的示例用于补充具体功能说明。

LIVE EXAMPLE UNIFORM GRID
全屏
正在启动 DirectSurface UI 运行时…

布局系统总览

DirectSurface UI 使用约束传递模型:父节点向子节点传递 BoxConstraints,子节点在约束内计算 size,父节点再为子节点设置 offset。业务代码应使用布局组件表达结构,不要在 performPaint() 中手工计算页面坐标。

可运行布局示例

UniformGrid 等分布局

LIVE CANVAS可运行组件示例
ON-DEMAND RUNTIME交互式示例将在进入视区时启动避免文档首屏同时初始化多个 Canvas Runtime

Anchor / Canvas 锚点定位

LIVE CANVAS可运行组件示例
ON-DEMAND RUNTIME交互式示例将在进入视区时启动避免文档首屏同时初始化多个 Canvas Runtime

Box / Panel 盒模型

LIVE CANVAS可运行组件示例
ON-DEMAND RUNTIME交互式示例将在进入视区时启动避免文档首屏同时初始化多个 Canvas Runtime

Visibility / Clip 状态与裁剪

LIVE CANVAS可运行组件示例
ON-DEMAND RUNTIME交互式示例将在进入视区时启动避免文档首屏同时初始化多个 Canvas Runtime

统一的组件布局属性

所有 RenderBox 组件都直接拥有以下属性,不再通过单子节点包装器补充尺寸、外边距或对齐能力:

属性 类型 说明
width / height number | undefined 期望内容尺寸;父级 tight 约束优先。
minWidth / maxWidth number | undefined 水平方向尺寸边界。
minHeight / maxHeight number | undefined 垂直方向尺寸边界。
margin EdgeInsetsInput 组件绘制区域之外、由直接父布局保留的空间。
horizontalAlignment BoxAlignment 在父布局分配槽位中的水平位置。
verticalAlignment BoxAlignment 在父布局分配槽位中的垂直位置。

BoxAlignment'start' | 'center' | 'end' | 'stretch'EdgeInsetsInput 支持数字和对象:

const title = new RenderText('患者列表')title.width = 240title.margin = { left: 12, right: 12, bottom: 8 }title.horizontalAlignment = 'center'

size 始终表示组件自身的绘制尺寸;outerSize 表示 size + margin。这一区分让背景、边框和命中区域不会错误地覆盖外边距。

自身对齐、父级分布和默认策略

horizontalAlignment / verticalAlignment 描述的是“组件自身如何放入直接父级分配的槽位”,不是“如何对齐自己的子组件”。属性值为 undefined 时,由直接父布局选择适合当前布局算法的默认策略;不同父容器不必使用同一个默认值。

直接父布局 未设置子项 alignment 时的默认策略
RenderStackPanel 主轴由排列和 mainAxisAlignment 统一分布;交叉轴使用 crossAxisAlignment,默认 start
RenderGridPanel / RenderUniformGrid 单元格内水平、垂直均为 stretch
RenderAdaptiveGridPanel 单元格内水平 stretch、垂直 start
RenderDockPanel Top/Bottom 水平 stretch;Left/Right 垂直 stretch;Fill 双轴 stretch。另一个方向默认 start
RenderWrapPanel 行内和行间位置由面板的 alignment / runAlignment 决定;行内交叉轴默认 start
RenderMasonryPanel 列内水平使用 itemHorizontalAlignment,默认 stretch;垂直位置由瀑布流顺序决定。
RenderAnchor / RenderCanvas 使用 top/right/bottom/left/centerX/centerY,普通 alignment 不参与锚点定位。
RenderOverlayHost base 始终接受宿主的双轴 tight 约束并填满宿主;overlay 默认双轴 center

RenderAnchor / RenderCanvas 的锚点轴和 RenderOverlayHost 的 base 外,子组件显式设置的 alignment 会覆盖有意义轴上的父级默认策略。alignment 只有在父级分配的槽位大于组件实际尺寸时才会产生可见偏移;如果组件已经占满槽位,设置 center 不会改变画面。

约束优先级

尺寸按以下顺序解析:

  1. 父布局给出的 tight 约束最高优先级,例如 Grid 轨道、Dock fill 和 StackPanel flex 分配。
  2. 在父约束允许时使用组件的 width / height
  3. minWidthmaxWidthminHeightmaxHeight 对结果限幅。
  4. 未指定期望尺寸时使用组件自然尺寸。

因此,固定大小直接设置组件属性即可,不需要额外的 SizedBox;局部居中直接设置 alignment,不需要额外的 Align 或 Center。

在 Grid、UniformGrid、Dock、Wrap、AdaptiveGrid、Masonry 和 overlay 槽位中,显式 width / height 会阻止对应轴上的默认 stretch 拉伸;如果没有再显式设置 centerend,固定尺寸组件仍停在槽位起点。需要固定尺寸居中时应同时设置尺寸边界和 alignment。父级明确给出 tight 约束时仍以父约束为准,例如 StackPanel 的 flex 主轴和 RenderOverlayHost 的 base。

全页居中表单

全页居中通常使用单格 Grid 提供完整页面槽位,再给表单容器设置宽度边界和自身 alignment。内层 Grid 只负责字段的行列对齐:

import { RenderBorder, RenderGridPanel, gridAuto, gridFr } from 'ds-ui' const formGrid = new RenderGridPanel({  columns: [gridFr(1)],  rows: [gridAuto()],}) const host = new RenderGridPanel({  columns: [gridFr(1)],  rows: [gridFr(1)],  padding: 24,}) const formCard = new RenderBorder({ child: formGrid })formCard.maxWidth = 520formCard.horizontalAlignment = 'center'formCard.verticalAlignment = 'center' host.addChild(formCard)

maxWidth 很重要:如果表单自身也是带 fr 列的 Grid,它会在没有宽度边界时占满外层单元格,此时虽然 alignment 已生效,但没有剩余空间可供居中。

Padding 属于容器

padding 表示容器边界与内容槽位之间的内部空间,只由能够承载内容的容器提供。主布局面板继承 RenderPanel,原生支持 padding

  • RenderStackPanel
  • RenderGridPanel
  • RenderDockPanel
  • RenderWrapPanel
  • RenderUniformGrid
  • RenderAdaptiveGridPanel
  • RenderMasonryPanel
  • RenderAnchor / RenderCanvas

单子节点视觉容器 RenderBorder 同样原生支持 padding

const content = new RenderStackPanel({  orientation: 'vertical',  spacing: 12,  padding: 24,  crossAxisAlignment: 'stretch',}) const saveButton = new RenderButton({ label: '保存', variant: 'primary' })saveButton.margin = { top: 8 }content.addChild(saveButton)

常规兄弟间距优先用 spacingrowGapcolumnGap;某一个子节点需要例外间距时才设置该节点的 margin

未显式配置间距时,布局阶段使用当前主题的 itemSpacing。由于公开 getter 没有布局主题上下文,此时读取 spacingrowGapcolumnGap 会得到 0;它表示“没有显式数值”,不是最终生效的主题间距。

常用结构容器

场景 推荐组件 说明
页面纵向结构、工具条、按钮组 RenderStackPanel 单方向排列,支持 flex 剩余空间分配。
顶部、底部、左右侧栏和主内容 RenderDockPanel 子项只声明 dock 方位,尺寸使用子组件自身属性。
表单、属性面板、严格行列对齐 RenderGridPanel 支持 px/fr/auto 轨道、跨行跨列;对齐使用子组件自身属性。
等宽等高入口 RenderUniformGrid 所有单元格尺寸一致。
标签、筛选条件自动换行 RenderWrapPanel 空间不足时自动换行。
响应式卡片列 RenderAdaptiveGridPanel 根据可用宽度计算列数。
高度不一致的卡片 RenderMasonryPanel 新项目进入当前最短列。
绝对定位、覆盖层、浮动按钮 RenderAnchor / RenderCanvas attached data 只描述边缘和中心锚点。
普通内容滚动 RenderScrollViewer 单子节点滚动容器;复杂数据组件通常自己管理滚动。

父布局附加数据只描述父级关系:

  • StackPanel:flex
  • DockPanel:dock
  • GridPanel:rowcolumnrowSpancolumnSpan
  • Anchor:toprightbottomleftcenterXcenterY

宽高、最小/最大尺寸、margin 和 alignment 始终属于子组件本身,避免同一能力出现两套状态来源。

StackPanel 与 flex

使用 addChild(child, flex) 分配剩余主轴空间:

const page = new RenderStackPanel({  orientation: 'vertical',  spacing: 8,  padding: 16,  crossAxisAlignment: 'stretch',}) page.addChild(new RenderPageHeader({ title: '订单列表' }))page.addChild(new RenderTextBox({ placeholder: '搜索订单' }))page.addChild(new RenderDataGrid({ columns: [], rows: [] }), 1)

flex = 0 在主轴按自然尺寸布局;flex > 0 按权重分配有限的剩余空间。主轴无界时 flex 子项也退化为自然尺寸。需要纯空白占位时使用 RenderSpacer

保留的行为型包装组件

以下组件保留,因为它们提供的是独立行为,不是重复的盒模型属性:

组件 独立职责
RenderVisibility 在 visible、hidden、collapsed 之间切换布局和命中行为。
RenderClip 裁剪子节点绘制和命中区域。
RenderAppContextScope 向子树提供局部 app context。
RenderCommandScope 向子树提供局部命令作用域。

滚动边界

RenderScrollViewer 适合普通内容。RenderDataGridRenderTreeViewRenderPlainTextEditorRenderMarkdownViewerRenderMedicalRecordEditor 通常自己管理滚动,不要在同一方向重复嵌套滚动容器。

相关文档