# AtomUI 媒体查询系统 — 开发者指南 > 本文档面向 AtomUI 控件使用者和控件开发者,介绍如何在 AXAML 和 C# 中使用媒体查询实现响应式布局。 --- ## 1. 概念:断点体系 AtomUI 遵循 Ant Design 5.0 的六级响应式断点。当窗口内容区域宽度达到某个阈值时,自动切换到对应断点: | 缩写 | 断点 | 最小宽度 | 说明 | |---|---|---|---| | `xs` | ExtraSmall | < 576px | 手机竖屏 | | `sm` | Small | ≥ 576px | 手机横屏 | | `md` | Medium | ≥ 768px | 平板竖屏 | | `lg` | Large | ≥ 992px | 小桌面(**默认**) | | `xl` | ExtraLarge | ≥ 1200px | 标准桌面 | | `xxl` | ExtraExtraLarge | ≥ 1600px | 大屏桌面 | > **前提**:应用的 `Window` 必须使用 AtomUI 提供的 `atom:Window`(而非 Avalonia 原生 `Window`),因为断点检测逻辑内置在 AtomUI Window 的主题模板中。 --- ## 2. Grid 栅格系统(Row / Col) AtomUI 的 `Row` + `Col` 组合实现了 Ant Design 的 24 栏栅格系统。`Row` 是容器,`Col` 是列。 ### 2.1 基础用法 ```xml ``` - `Span` 指定列跨度(1~24)。 - `Gutter` 指定水平和垂直间距(`"水平,垂直"` 格式)。 ### 2.2 响应式列跨度 通过 `Col` 的 `Xs`、`Sm`、`Md`、`Lg`、`Xl`、`Xxl` 属性,为不同断点设置不同的布局配置: ```xml ``` 当窗口宽度 < 576px 时(`xs`),每列占满整行(24/24);宽度 ≥ 576px 时(`sm`),每行两列(12/24);宽度 ≥ 992px 时(`lg`),每行四列(6/24)。 **字符串格式**:断点属性的值可以是: - **纯数字**:`"12"` → 仅设置 Span - **键值对**:`"span:12,offset:2,order:1"` → 设置多个布局属性 ### 2.3 使用 ColInfo 进行高级响应式覆盖 `ColInfo` 是 `GridColSize` 的别名,支持在特定断点下完整覆盖 Span、Offset、Order、Push、Pull: **方式一:属性元素语法** ```xml ``` **方式二:标记扩展语法** ```xml ``` **方式三:StaticResource 共享** ```xml ``` ### 2.4 响应式 Span `Col.Span` 属性也支持按断点指定不同的值: ```xml ``` ### 2.5 响应式 Gutter `Row.Gutter` 支持按断点设置不同的间距: ```xml ... ... ... ... ``` ### 2.6 Offset / Push / Pull / Order ```xml ... ... ... ... ... ... ... ``` ### 2.7 Justify 和 Align ```xml ... ... ... ... ... ... ... ... ``` --- ## 3. Form 表单响应式布局 `Form` 和 `FormItem` 的标签/内容列宽可以通过 `MediaBreakGridLength` 实现响应式: ### 3.1 基本用法 ```xml ``` - `LabelColInfo`:标签列的 GridLength,按断点配置。 - `WrapperColInfo`:内容列的 GridLength,按断点配置。 - 值格式支持标准 GridLength 语法:`"120"`(像素)、`"*"`(比例)、`"Auto"`、`"2*"`(2 倍比例)。 ### 3.2 字符串格式 ``` "xs:1*,lg:120" ``` 解析规则: - 逗号分隔多个断点设置 - 每个断点格式为 `缩写:GridLength值` - 支持的缩写:`xs`、`sm`、`md`、`lg`、`xl`、`xxl` - 单一值(无冒号)应用于所有断点:`"120"` → 所有断点均 120px ### 3.3 FormItem 级别覆盖 `FormItem` 也有自己的 `LabelColInfo` 和 `WrapperColInfo` 属性,可以覆盖 `Form` 级别的设置: ```xml ``` --- ## 4. Descriptions 描述列表 `Descriptions` 控件的列数支持响应式配置: ### 4.1 基本用法 ```xml ``` ### 4.2 响应式列数 ```xml ``` ### 4.3 响应式项目跨度 `DescriptionItem.Span` 属性也支持按断点配置: ```xml ``` --- ## 5. 控件开发者:如何创建响应式控件 如果你正在为 AtomUI 开发新控件并需要响应断点变化,请遵循以下模式。 ### 5.1 订阅断点变更 ```csharp using AtomUI.Controls; using Avalonia; using Avalonia.Controls; namespace AtomUI.Desktop.Controls; public class MyResponsiveControl : Control { private MediaBreakPoint? _breakPoint; private IMediaBreakAwareControl? _mediaOwner; protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); // 通过接口获取(推荐,更通用) if (TopLevel.GetTopLevel(this) is IMediaBreakAwareControl mediaOwner) { _mediaOwner = mediaOwner; _breakPoint = mediaOwner.MediaBreakPoint; mediaOwner.MediaBreakPointChanged += HandleMediaBreakChanged; } } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); if (_mediaOwner != null) { _mediaOwner.MediaBreakPointChanged -= HandleMediaBreakChanged; _mediaOwner = null; } } private void HandleMediaBreakChanged(object? sender, MediaBreakPointChangedEventArgs args) { _breakPoint = args.MediaBreakPoint; // 触发重新布局或刷新状态 InvalidateMeasure(); InvalidateArrange(); } private MediaBreakPoint GetBreakPoint() { if (_breakPoint.HasValue) { return _breakPoint.Value; } // 降级:尝试即时获取 if (TopLevel.GetTopLevel(this) is IMediaBreakAwareControl mediaOwner) { _breakPoint = mediaOwner.MediaBreakPoint; return _breakPoint.Value; } // 最终降级:使用默认值 return MediaBreakPoint.Large; } } ``` ### 5.2 定义响应式断点信息类型 如果你的控件需要一个新的响应式属性(类似 `GridGutterInfo`),遵循已有的 record 模式: ```csharp public record MyMediaBreakInfo { public double ExtraSmall { get; init; } public double Small { get; init; } public double Medium { get; init; } public double Large { get; init; } public double ExtraLarge { get; init; } public double ExtraExtraLarge { get; init; } // 统一值构造 public MyMediaBreakInfo(double value) { ExtraSmall = Small = Medium = Large = ExtraLarge = ExtraExtraLarge = value; } // 按断点获取值 public double GetValue(MediaBreakPoint breakPoint) { return breakPoint switch { MediaBreakPoint.ExtraSmall => ExtraSmall, MediaBreakPoint.Small => Small, MediaBreakPoint.Medium => Medium, MediaBreakPoint.Large => Large, MediaBreakPoint.ExtraLarge => ExtraLarge, _ => ExtraExtraLarge }; } // 支持 "xs:10,lg:20" 格式的字符串解析 public static MyMediaBreakInfo Parse(string input) { ... } } ``` 关键约定: - 使用 `record` 类型,支持 `with` 表达式。 - 提供统一值构造函数(所有断点相同)。 - 提供 `Parse(string)` 方法,支持 `缩写:值` 的逗号分隔格式。 - 断点缩写统一为小写:`xs`、`sm`、`md`、`lg`、`xl`、`xxl`(解析时忽略大小写)。 - 如果需要 AXAML 字符串转换,提供 `TypeConverter`。 ### 5.3 字符串格式规范 所有响应式属性的字符串解析遵循统一规范: ``` 单一值: "16" → 所有断点使用 16 分断点(逗号分隔): "xs:8,sm:16,lg:24" → xs=8, sm=16, lg=24, 未指定的保持默认值 键值对分隔符: 冒号 (:) → 断点名与值之间 逗号 (,) → 多个断点之间 分号 (;) → 仅 GridGutter: 水平与垂直之间 ``` --- ## 6. 底层原理:Avalonia Container Query AtomUI 的媒体查询构建在 Avalonia 的 Container Query 功能之上。理解底层机制有助于排查问题。 ### 6.1 核心概念 1. **Container(容器)**:通过 `Container.Name` 和 `Container.Sizing` 附加属性声明。容器会跟踪自身尺寸。 2. **ContainerQuery**:声明在 `ControlTheme` 或 `Styles` 中的查询规则。当关联容器的尺寸满足条件时,激活内部的 Style。 3. **查询语法**: - `min-width:576` → 宽度 ≥ 576px 时激活 - `max-width:575` → 宽度 ≤ 575px 时激活 - `min-width:400 and max-width:800` → 宽度在 400~800px 之间 - `max-width:300,min-height:600` → 宽度 ≤ 300px **或** 高度 ≥ 600px ### 6.2 AtomUI 的封装 AtomUI 没有直接让每个控件自行声明 ContainerQuery。而是: 1. **Window 的主题模板**中声明了一个全局容器 `PART_GlobalQueryContainer`。 2. 6 组 `ContainerQuery` 监听此容器的宽度变化。 3. 匹配时设置一个不可见的 `WindowMediaQueryIndicator` 控件的 `MediaBreakPoint` 属性。 4. `WindowMediaQueryIndicator` 将变更通知给 `Window`。 5. `Window` 通过 `MediaBreakPointChanged` 事件广播给所有订阅者。 这种集中式设计的优势: - **单一检测点**:只有一个容器查询管道,避免重复计算。 - **统一断点**:所有控件始终看到相同的断点值。 - **可预测性**:断点变更的时序和顺序是确定的。 ### 6.3 限制与注意事项 1. **必须使用 `atom:Window`**:标准 Avalonia `Window` 不包含 ContainerQuery 声明,断点不会生效。 2. **ContainerQuery 不能影响容器本身**:这是 Avalonia 的设计约束,因此需要 `WindowMediaQueryIndicator` 作为中继。 3. **断点基于内容区域宽度**:不是整个窗口宽度,而是 `ContentFrame`(扣除标题栏和 Padding 后的区域)的宽度。 4. **默认断点是 `Large`**:如果控件在附加到视觉树之前需要断点信息,应使用 `MediaBreakPoint.Large` 作为回退值。 --- ## 7. 完整示例 ### 7.1 响应式三栏布局 ```xml ``` ### 7.2 响应式表单 ```xml ``` ### 7.3 响应式描述列表 ```xml ``` ### 7.4 响应式列序变换 ```xml ```