Files
AtomUI/docs/modules/controls-shared/responsive-system.md
T

12 KiB
Raw Blame History

AtomUI 响应式机制设计

本文档定义 AtomUI 控件体系的响应式基础机制。该机制对齐 Ant Design 6 的响应式设计,用于 Grid、Descriptions、Masonry 以及其他需要按媒体断点解析公共属性的控件。

响应式机制属于 AtomUI.Controls.Shared 的跨控件基础能力。具体控件文档只描述该控件如何消费响应式值,不重复断点定义、解析顺序和 fallback 规则。

1. 定位

响应式机制负责把“当前媒体断点”和“用户声明的响应式配置”解析为控件可直接消费的有效值。

它提供三类能力:

  • 统一媒体断点集合、顺序和 Token 来源。
  • 统一 partial breakpoint map 的解析和求值规则。
  • 统一 XAML 字符串格式、显式配置记录、fallback 处理边界和验证策略。

它不负责具体控件布局算法。Grid、Descriptions、Masonry 只消费解析后的有效值,并保留各自的布局、夹取、默认值和视觉契约。

2. Ant Design 对齐规则

AtomUI 响应式规则与 Ant Design 的以下设计保持一致:

  • xs / sm / md / lg / xl / xxl / xxxl 是统一断点集合。
  • active screen 采用累计语义。当前为 lg 时,xs、sm、md、lg 均视为 active。
  • partial breakpoint map 采用 mobile-first cascade。未配置的更大断点继承最近的较小断点配置。
  • 求值时按 xxxl -> xxl -> xl -> lg -> md -> sm -> xs 从大到小查找,第一个“当前 active 且显式配置过”的值生效。
  • 响应式解析器不拥有控件默认值。默认值由具体控件在 resolver 未命中时提供。

Ant Design 源码对应关系:

能力 Ant Design 源码
断点顺序与 matchScreen .referenceprojects/ant-design/components/_util/responsiveObserver.ts
Grid Row gutter / align / justify .referenceprojects/ant-design/components/grid/row.tsx、.referenceprojects/ant-design/components/grid/hooks/useGutter.ts
Grid Col responsive class .referenceprojects/ant-design/components/grid/col.tsx、.referenceprojects/ant-design/components/grid/style/index.ts
Descriptions column 与 span .referenceprojects/ant-design/components/descriptions/index.tsx、.referenceprojects/ant-design/components/descriptions/hooks/useItems.ts
Masonry columns 与 gutter .referenceprojects/ant-design/components/masonry/Masonry.tsx

3. 断点模型

AtomUI 的媒体断点必须以 Alias Token 为唯一数值来源。

短名 MediaBreakPoint 起始 Token 结束 Token Ant Design 名称
xs ExtraSmall 无 ScreenSMMin - 1 xs
sm Small ScreenSMMin ScreenSMMax sm
md Medium ScreenMDMin ScreenMDMax md
lg Large ScreenLGMin ScreenLGMax lg
xl ExtraLarge ScreenXLMin ScreenXLMax xl
xxl ExtraExtraLarge ScreenXXLMin ScreenXXLMax xxl
xxxl ExtraExtraExtraLarge ScreenXXXLMin 无 xxxl

Token 要求:

  • ScreenXXXL 与 ScreenXXXLMin 是 Ant Design 6 对齐所需 Token。
  • ScreenXXLMax 必须等于 ScreenXXXLMin - 1。
  • ScreenXS、ScreenXSMin、ScreenXSMax 保留 Ant Design Token 兼容语义;运行时 xs 当前断点范围以 ScreenSMMin - 1 为上界。
  • MediaBreakPoint 枚举值必须按从小到大排列,保证 current >= configured 可表达 mobile-first cascade。

4. Active Screen 与求值

响应式解析器以当前断点构造 active screen 集合。

current = lg
active = xs, sm, md, lg

current = xxxl
active = xs, sm, md, lg, xl, xxl, xxxl

求值顺序固定为:

xxxl -> xxl -> xl -> lg -> md -> sm -> xs

求值规则:

Resolve(current, map, fallback)
  for key in descending breakpoint order:
    if key is active for current and map explicitly contains key:
      return map[key]
  return fallback

示例:

当前断点 配置 结果
xs xs: 1, md: 3 1
sm xs: 1, md: 3 1
md xs: 1, md: 3 3
lg xs: 1, md: 3 3
xxl xl: 4,fallback 3 4
sm xl: 4,fallback 2 2

解析器必须区分“未配置”和“配置值等于默认值”。不得在 Parse 阶段用默认值填满所有断点。

5. XAML 与公共 API 形态

响应式公共 API 必须同时满足 Avalonia 属性系统、XAML 可读性、AOT 兼容和控件语义。

5.1 属性注册

控件公开响应式属性时,必须声明对应 Avalonia 静态属性和 CLR wrapper。

public static readonly StyledProperty<ResponsiveInt?> ColumnInfoProperty =
    AvaloniaProperty.Register<Masonry, ResponsiveInt?>(nameof(ColumnInfo));

public ResponsiveInt? ColumnInfo
{
    get => GetValue(ColumnInfoProperty);
    set => SetValue(ColumnInfoProperty, value);
}

attached responsive property 必须同样提供 AttachedProperty、GetXxx、SetXxx。

5.2 标准响应式类型

响应式值类型分为公共 XAML 友好类型和底层共享求值器。标准类型按值域命名,而不是按控件命名:

值域 标准类型 用途
整数 ResponsiveInt 列数、span、order 等整数型响应式值
浮点数 ResponsiveDouble 间距、尺寸等数值型响应式值
GridLength ResponsiveGridLength 表单、布局中按断点变化的 GridLength
双向间距 ResponsiveGutter Row、Masonry 等水平/垂直 gutter
枚举 专项 wrapper RowAlign、RowJustify 等枚举值,内部仍委托共享 resolver

标准类型要求:

  • 必须能表达 scalar 固定值和 partial breakpoint map。
  • 必须记录哪些断点由用户显式配置。
  • 必须委托底层共享求值器完成断点排序、显式配置检查和 fallback 处理。
  • 不允许每个控件各自复制 breakpoint parser 和 switch 逻辑。
  • 不再为单个控件新增 DescriptionsMediaBreakInfo 这类只服务单控件且复制规则的类型;既有同类类型完成标准 API 迁移后应删除。

5.3 字符串格式

响应式值必须支持以下 XAML 字符串格式:

ColumnInfo="3"
ColumnInfo="xs: 1, md: 3, xl: 4"
Gutter="16"
Gutter="16, 24"
Gutter="xs: 8, md: 16"

格式规则:

  • scalar 值表示所有断点固定为同一值。
  • Gutter scalar 值表示水平和垂直两个维度使用同一固定值。
  • breakpoint map 只记录显式出现的断点。
  • breakpoint key 大小写不敏感,但文档和示例统一使用小写。
  • 未知 breakpoint、空 key、空 value、非法数值必须抛出明确异常。
  • 重复 breakpoint key 必须抛出明确异常,避免字符串配置产生顺序依赖。
  • 计数类值必须大于 0;间距类值必须大于等于 0;具体值域的合法范围由标准类型负责校验。
  • Gutter 类值按 Ant Design Row 语义支持水平、垂直两个维度;两个维度分别使用同一套 responsive resolver。

6. 控件集成规则

6.1 Grid

Grid 是响应式机制的基准控件。

Col 的 Xs / Sm / Md / Lg / Xl / Xxl / Xxxl 断点属性属于显式 breakpoint 配置。解析时先建立基础布局,再按从小到大顺序应用当前断点以内的显式配置,等价于“取当前 active 范围内最大的已配置断点”。

Col.Flex 对齐 Ant Design flex 语义,用于填充行内剩余空间。数值表示 flex grow/shrink,auto 表示自动基准的 flex 项,none 表示不伸缩,100px 这类固定像素基准表示固定 basis。断点级 GridColSize.Flex 会覆盖基础 span 宽度并参与同一行的剩余空间分配。

Col.Span=0 和断点级 GridColSize.Span=0 表示隐藏该列,布局时不占用行宽,并在 arrange 阶段收敛到零尺寸,等价于 Ant Design 的 display: none 语义。未显式设置 Span 的 Col 仍保持自然宽度行为,不能因为默认 GridColSpanInfo 为 0 而被误判为隐藏。

Row.Gutter 的水平和垂直间距分别使用响应式 resolver。水平 gutter 必须对齐 Ant Design 的 Row 负 margin + Col padding 模型:间距只出现在列之间,不出现在 Row 两端;实现上通过扩展 Row 的内部布局面并从 -gutter / 2 开始排布来抵消首尾半个 gutter。

Row.JustifyInfo 与 Row.AlignInfo 为响应式覆盖入口,未设置时完全沿用 Row.Justify 与 Row.Align。响应式行对齐必须使用同一套 resolver,不能引入单独解析规则。

6.2 Descriptions

Descriptions.ColumnInfo 表示每行 DescriptionItem 数量。它必须按 Ant Design column 语义解析 partial breakpoint map。

默认 fallback map:

断点 默认列数
xs 1
sm 2
md 3
lg 3
xl 3
xxl 3
xxxl 4

DescriptionItem.Span 表示 item 跨列数量。未声明时 fallback 为 1;声明为 partial map 时同样使用 mobile-first cascade。IsFilled 表示填满当前行剩余空间,优先级高于解析后的 span 数值。

6.3 Masonry

Masonry.ColumnInfo 表示 Ant Design columns 对齐 API,接受 scalar 或 partial breakpoint map。

列数优先级:

  1. ColumnInfo 命中当前断点时,使用响应式列数。
  2. ColumnCount > 0 时,使用固定列数。
  3. 使用 MinColumnWidth + MaxColumnCount + AvailableWidth 的容器自适应列数。

Masonry.Gutter 表示 Ant Design gutter 对齐 API,支持 scalar、水平/垂直 pair、responsive map 和水平/垂直 responsive pair。

间距优先级:

  1. Gutter 命中当前断点时,使用响应式水平/垂直间距。
  2. 使用兼容属性 ColumnGap 与 RowGap。

Masonry 的 shortest-column 布局、整行项、显式列、ItemsSource 容器模型和 LayoutChanged 事件不属于响应式 resolver 职责。

7. Fallback 边界

共享 resolver 只回答“用户配置在当前断点是否命中”。它不内置任何控件默认值。

控件必须在自己的 effective state 层提供 fallback:

  • Grid 负责 24 栅格默认 span、offset、order、push、pull。
  • Descriptions 负责默认列数 map、默认 item span 和 bordered 布局换算。
  • Masonry 负责默认列数、容器自适应列数和默认间距。

该边界保证新增控件可以复用同一套 responsive resolver,同时保留自身业务语义。

8. 生命周期与性能

响应式控件通过 MediaQueryHost.FindOwner 获取最近的 IMediaBreakAwareControl,并订阅 MediaBreakPointChanged。

维护要求:

  • 订阅必须在 detached 或 owner 替换时释放。
  • breakpoint 变化只更新 effective state 并触发布局失效,不在事件回调中直接执行完整布局。
  • 影响 layout 的响应式属性必须注册 AffectsMeasure 或在属性变更路径中触发父级布局失效。
  • resolver 必须是无视觉依赖、无全局状态的纯计算逻辑。
  • parser 与 resolver 不依赖 reflection,不要求运行时动态生成代码,保持 NativeAOT 兼容。

9. 兼容性不变量

响应式机制变更必须保持以下不变量:

  • 同一配置在 Grid、Descriptions、Masonry 中使用相同断点集合和继承规则。
  • partial map 不得在解析阶段被默认值填满。
  • scalar 配置必须保持跨断点固定值语义。
  • 控件 fallback 不得泄漏进共享 resolver。
  • xxxl 是合法断点,文档、parser、resolver、Token 和媒体断点枚举必须一致。
  • 公共响应式属性必须遵守 Avalonia 属性注册规范。
  • XAML 示例中的短名 xs / sm / md / lg / xl / xxl / xxxl 是稳定契约。

10. 验证策略

共享响应式机制至少需要覆盖以下测试:

  • xs / sm / md / lg / xl / xxl / xxxl key 解析。
  • scalar 值在所有断点下返回同一结果。
  • partial map 在大屏继承最近较小断点。
  • 当前断点小于所有显式配置时返回控件 fallback。
  • 0、空字符串、未知 key、非法数字、重复 key 的处理符合对应值类型约束。
  • Gutter 水平和垂直维度独立解析。
  • MediaBreakPointChanged 只触发布局失效,不重复订阅或泄漏 owner。

控件级验证:

  • Grid 验证 Col 断点属性、Row.Gutter 和响应式 align/justify 的有效状态。
  • Descriptions 验证 ColumnInfo="xs: 1, md: 3" 在 lg 下解析为 3,并验证 item Span 同规则。
  • Masonry 验证 ColumnInfo 优先级、Gutter 优先级和 fallback 到容器自适应列数。

文档验证:

git diff --check