Files
LanMountainDesktop/docs/03-组件设计规范/03-布局规范.md

679 lines
18 KiB
Markdown
Raw Normal View History

# 布局规范
本文档详细说明组件布局规范,包括**安全区域**、间距系统、网格系统和响应式布局。
## 🎯 布局目标
良好的布局应该:
- ✅ 内容不会被截断或溢出
- ✅ 视觉元素对齐整齐
- ✅ 留白充足,不拥挤
- ✅ 适配不同的组件尺寸
- ✅ 易于维护和扩展
## 📐 安全区域Safe Area
### 什么是安全区域?
**安全区域**是组件内容必须保持的最小边距,确保内容不会紧贴组件边缘,保持视觉舒适度。
```
┌─────────────────────────────────────────┐
│ ◄─────── 16px 安全边距 ───────► │
│ ▲ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 这是内容安全区域 │ │ │
│ │ │ 所有内容都应该在这里 │ │ │
│ 16px│ 不要紧贴边缘 │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ ▼ │
│ ◄─────── 16px 安全边距 ───────► │
└─────────────────────────────────────────┘
```
### 安全区域标准
| 位置 | 最小边距 | 推荐边距 | 说明 |
|-----|---------|---------|------|
| **上边距** | 16px | 16-20px | 顶部内容到边缘 |
| **下边距** | 16px | 16-20px | 底部内容到边缘 |
| **左边距** | 16px | 16-24px | 左侧内容到边缘 |
| **右边距** | 16px | 16-24px | 右侧内容到边缘 |
### AXAML 实现
```xml
<!-- ✅ 正确:使用 Padding 创建安全区域 -->
<Border Background="{DynamicResource CardBackgroundBrush}"
CornerRadius="8"
Padding="16">
<!-- 内容区域 -->
<StackPanel Spacing="8">
<TextBlock Text="标题" FontSize="16"/>
<TextBlock Text="内容" FontSize="14"/>
</StackPanel>
</Border>
<!-- ✅ 使用设计资源 -->
<Border Background="{DynamicResource CardBackgroundBrush}"
CornerRadius="{DynamicResource DesignCornerRadiusComponent}"
Padding="{DynamicResource DesignPaddingComponent}">
<!-- 内容 -->
</Border>
<!-- ❌ 错误:没有安全边距 -->
<Border Background="{DynamicResource CardBackgroundBrush}"
CornerRadius="8">
<!-- 内容会紧贴边缘,不美观 -->
<TextBlock Text="标题"/>
</Border>
```
### 不同 Padding 配置
```xml
<!-- 统一边距 -->
<Border Padding="16">...</Border>
<!-- 左右、上下不同 -->
<Border Padding="16,12">...</Border>
<!-- 等价于: Left=Right=16, Top=Bottom=12 -->
<!-- 四个方向分别指定 -->
<Border Padding="16,12,16,20">...</Border>
<!-- 顺序: Left, Top, Right, Bottom -->
<!-- 使用 Thickness -->
<Border>
<Border.Padding>
<Thickness Left="16" Top="12" Right="16" Bottom="20"/>
</Border.Padding>
</Border>
```
### 安全区域示例
**天气组件示例**:
```xml
<Border Width="200" Height="150"
Background="{DynamicResource CardBackgroundBrush}"
CornerRadius="8"
Padding="16">
<Grid RowDefinitions="Auto,*,Auto">
<!-- 顶部:位置信息(距离顶边 16px -->
<TextBlock Grid.Row="0"
Text="📍 北京"
FontSize="14"/>
<!-- 中间:主要信息 -->
<StackPanel Grid.Row="1"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBlock Text="☀️" FontSize="48"/>
<TextBlock Text="25°C" FontSize="32"/>
</StackPanel>
<!-- 底部:操作按钮(距离底边 16px -->
<StackPanel Grid.Row="2"
Orientation="Horizontal"
HorizontalAlignment="Right"
Spacing="8">
<Button Content="🔄" Padding="8,4"/>
<Button Content="⚙️" Padding="8,4"/>
</StackPanel>
</Grid>
</Border>
```
**可视化布局**:
```
┌────────────────────────────────┐
│ ◄─── 16px ───► │ ▲
│ ▲ │ │
│ │ 📍 北京 │ │ 16px
│ │ │ │
│ │ ☀️ │ ▼
│ 16px 25°C │
│ │ 晴 │
│ │ │ ▲
│ │ [🔄] [⚙️] │ │ 16px
│ ▼ │ │
│ ◄─── 16px ───► │ ▼
└────────────────────────────────┘
```
## 📏 间距系统
### 间距标准
阑山桌面使用 **4px 基础网格**,所有间距都是 4 的倍数。
| 名称 | 值 | 用途 | 使用场景 |
|-----|---|------|---------|
| **XXS** | 2px | 最小间距 | 边框到内容、图标微调 |
| **XS** | 4px | 紧密间距 | 相邻标签、图标与文字 |
| **S** | 8px | 小间距 | 相关元素之间 |
| **M** | 12px | 中间距 | 元素组之间 |
| **L** | 16px | 大间距 | 区块之间、安全边距 |
| **XL** | 24px | 超大间距 | 重要区块分隔 |
| **XXL** | 32px | 巨大间距 | 页面级分隔 |
### 间距使用场景
#### 1. 垂直间距Vertical Spacing
```xml
<StackPanel Spacing="8">
<!-- 元素 1 -->
<TextBlock Text="标题"/>
<!-- ↕ 8px 间距 -->
<!-- 元素 2 -->
<TextBlock Text="内容"/>
<!-- ↕ 8px 间距 -->
<!-- 元素 3 -->
<Button Content="操作"/>
</StackPanel>
```
**垂直间距指南**:
```
相关元素(标题和内容): 8px
不同区块: 16px
独立功能区: 24px
示例:
┌──────────────────┐
│ 📍 北京 │ ← 标题
│ ↕ 8px │
│ 今天天气不错 │ ← 内容
│ ↕ 16px │ ← 区块分隔
│ ☀️ │
│ 25°C │
│ ↕ 16px │ ← 区块分隔
│ [刷新] [设置] │
└──────────────────┘
```
#### 2. 水平间距Horizontal Spacing
```xml
<StackPanel Orientation="Horizontal" Spacing="8">
<!-- 元素 1 -->
<Button Content="按钮1"/>
<!-- ↔ 8px 间距 -->
<!-- 元素 2 -->
<Button Content="按钮2"/>
</StackPanel>
```
**水平间距指南**:
```
图标和文字: 4px
相关按钮: 8px
独立按钮: 12px
示例:
[🔄] ← 4px → 刷新 ← 8px → [⚙️] ← 4px → 设置
```
#### 3. 网格间距Grid Spacing
```xml
<Grid ColumnDefinitions="*,8,*" RowDefinitions="*,8,*">
<!-- 列间距: 8px, 行间距: 8px -->
<Border Grid.Column="0" Grid.Row="0" Background="Red"/>
<Border Grid.Column="2" Grid.Row="0" Background="Blue"/>
<Border Grid.Column="0" Grid.Row="2" Background="Green"/>
<Border Grid.Column="2" Grid.Row="2" Background="Yellow"/>
</Grid>
```
### AXAML 间距资源
```xml
<!-- 定义间距资源 -->
<ResourceDictionary>
<Thickness x:Key="SpacingXXS">2</Thickness>
<Thickness x:Key="SpacingXS">4</Thickness>
<Thickness x:Key="SpacingS">8</Thickness>
<Thickness x:Key="SpacingM">12</Thickness>
<Thickness x:Key="SpacingL">16</Thickness>
<Thickness x:Key="SpacingXL">24</Thickness>
<Thickness x:Key="SpacingXXL">32</Thickness>
</ResourceDictionary>
<!-- 使用间距资源 -->
<Border Margin="{StaticResource SpacingL}">
<StackPanel Spacing="8">
<!-- 内容 -->
</StackPanel>
</Border>
```
## 🔲 网格系统
### 4px 基础网格
所有元素的位置、尺寸、间距都应该对齐到 **4px 的倍数**
```
0px 4px 8px 12px 16px 20px 24px 28px 32px
│ │ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ │ │ │ │ │ │ │ │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│ │ │ │ │ │ │ │ │
```
**为什么是 4px**
- ✅ 足够小,提供精细控制
- ✅ 是 8 和 16 的因子,便于计算
- ✅ 符合 Windows 11 设计规范
- ✅ 在高 DPI 屏幕上显示良好
### 对齐示例
```
❌ 错误:未对齐网格
┌──────────────┐
│ Padding: 15px│ ← 15 不是 4 的倍数
│ Width: 203px │ ← 203 不是 4 的倍数
└──────────────┘
✅ 正确:对齐到网格
┌──────────────┐
│ Padding: 16px│ ← 16 = 4 × 4
│ Width: 200px │ ← 200 = 4 × 50
└──────────────┘
```
### 常用尺寸
**符合 4px 网格的常用尺寸**:
| 用途 | 尺寸选项px |
|-----|---------------|
| **按钮高度** | 28, 32, 36, 40 |
| **图标尺寸** | 12, 16, 20, 24, 32, 48 |
| **组件宽度** | 120, 160, 200, 240, 280, 320, 400 |
| **组件高度** | 80, 120, 160, 200, 240, 280, 320 |
## 📦 组件尺寸规范
### 最小尺寸
```
┌─────────────────────┐
│ 最小宽度: 120px │
│ 最小高度: 80px │
│ │
│ 保证可读性和可用性 │
└─────────────────────┘
```
**最小尺寸要求**:
- ✅ 宽度 ≥ 120px - 保证文字不会过度换行
- ✅ 高度 ≥ 80px - 保证内容有足够空间
- ✅ 按钮 ≥ 32×32px - 保证可点击性
### 推荐尺寸
**小型组件120-150px**:
```
┌──────────────┐
│ 📍 北京 │
│ │
│ ☀️ │
│ 25°C │
└──────────────┘
120×80 - 150×100
适合: 单一信息、时钟、倒计时
```
**中型组件200-300px**:
```
┌────────────────────────┐
│ 📍 北京 │
│ │
│ ☀️ │
│ 25°C │
│ 晴 │
│ │
│ 今天: 18-30°C │
│ 湿度: 60% 风速: 3m/s │
│ │
│ [🔄] [⚙️] │
└────────────────────────┘
200×150 - 300×250
适合: 天气、日历、待办、便签
```
**大型组件350-500px**:
```
┌────────────────────────────────────────┐
│ 📅 本周日程 │
│ │
│ 周一 │
│ 09:00 - 10:00 团队会议 │
│ 14:00 - 15:30 项目评审 │
│ │
│ 周二 │
│ 10:00 - 11:00 客户沟通 │
│ ... │
│ │
│ [查看更多] │
└────────────────────────────────────────┘
350×300 - 500×400
适合: 日程、系统监控、新闻列表
```
### 宽高比建议
| 组件类型 | 推荐比例 | 示例尺寸 |
|---------|---------|---------|
| **正方形** | 1:1 | 120×120, 200×200 |
| **横向** | 4:3 | 200×150, 320×240 |
| **宽屏** | 16:9 | 320×180, 400×225 |
| **竖向** | 3:4 | 150×200, 240×320 |
## 🎯 响应式布局
### 尺寸适配
组件应该优雅地适配不同尺寸:
```csharp
public class WeatherComponent : ComponentBase
{
// 监听尺寸变化
protected override void OnSizeChanged(Size newSize)
{
if (newSize.Width < 180)
{
// 小尺寸:简化布局
ShowCompactLayout();
}
else if (newSize.Width < 300)
{
// 中等尺寸:标准布局
ShowNormalLayout();
}
else
{
// 大尺寸:详细布局
ShowDetailedLayout();
}
}
}
```
### 内容裁剪策略
**文本裁剪**:
```xml
<!-- 单行文本,超出显示省略号 -->
<TextBlock Text="这是一段很长的文字..."
TextTrimming="CharacterEllipsis"
MaxLines="1"/>
<!-- 多行文本,最多显示 2 行 -->
<TextBlock Text="这是一段很长的文字..."
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
MaxLines="2"/>
```
**内容溢出处理**:
```xml
<!-- 使用 ScrollViewer 处理溢出 -->
<ScrollViewer MaxHeight="200"
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Items}">
<!-- 列表项 -->
</ItemsControl>
</ScrollViewer>
```
### 断点设计
| 断点名称 | 宽度范围 | 布局策略 |
|---------|---------|---------|
| **XS** | < 160px | 极简布局,只显示核心信息 |
| **S** | 160-240px | 简化布局,隐藏次要信息 |
| **M** | 240-360px | 标准布局,显示主要信息 |
| **L** | 360-480px | 详细布局,显示完整信息 |
| **XL** | > 480px | 丰富布局,显示扩展信息 |
### 响应式示例
**小尺寸(< 160px**:
```
┌──────────┐
│ ☀️ │
│ 25°C │
└──────────┘
只显示图标和温度
```
**中尺寸200px**:
```
┌────────────────┐
│ 📍 北京 │
│ │
│ ☀️ │
│ 25°C │
│ 晴 │
│ │
│ 🔄 ⚙️ │
└────────────────┘
显示位置、天气、操作
```
**大尺寸300px**:
```
┌──────────────────────────┐
│ 📍 北京 │
│ │
│ ☀️ │
│ 25°C │
│ 晴 │
│ │
│ 今天: 18-30°C │
│ 湿度: 60% 风速: 3m/s │
│ 空气质量: 良 │
│ │
│ [刷新] [设置] │
└──────────────────────────┘
显示详细信息
```
## 📐 对齐指南
### 水平对齐
```xml
<!-- 左对齐 -->
<StackPanel HorizontalAlignment="Left">
<TextBlock Text="左对齐"/>
</StackPanel>
<!-- 居中对齐 -->
<StackPanel HorizontalAlignment="Center">
<TextBlock Text="居中对齐"/>
</StackPanel>
<!-- 右对齐 -->
<StackPanel HorizontalAlignment="Right">
<TextBlock Text="右对齐"/>
</StackPanel>
<!-- 拉伸(占满宽度) -->
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="拉伸"/>
</StackPanel>
```
### 垂直对齐
```xml
<!-- 顶部对齐 -->
<Grid>
<StackPanel VerticalAlignment="Top">
<TextBlock Text="顶部"/>
</StackPanel>
</Grid>
<!-- 居中对齐 -->
<Grid>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="居中"/>
</StackPanel>
</Grid>
<!-- 底部对齐 -->
<Grid>
<StackPanel VerticalAlignment="Bottom">
<TextBlock Text="底部"/>
</StackPanel>
</Grid>
```
### 对齐最佳实践
```
✅ 好的对齐:
┌──────────────────┐
│ 标题 │ ← 左对齐
│ │
│ 25°C │ ← 居中对齐
│ │
│ [按钮] │ ← 右对齐
└──────────────────┘
❌ 差的对齐:
┌──────────────────┐
│ 标题 │ ← 随意对齐
│ │
│ 25°C │ ← 不一致
│ │
│ [按钮] │ ← 混乱
└──────────────────┘
```
## 🛠️ 实用工具
### 布局调试
```xml
<!-- 开发时显示边界 -->
<Border BorderBrush="Red" BorderThickness="1">
<StackPanel>
<!-- 内容 -->
</StackPanel>
</Border>
<!-- 显示网格线 -->
<Grid ShowGridLines="True">
<!-- 内容 -->
</Grid>
```
### 布局助手类
```csharp
public static class LayoutHelper
{
// 对齐到 4px 网格
public static double AlignToGrid(double value)
{
return Math.Round(value / 4) * 4;
}
// 计算安全区域
public static Thickness SafeArea(double padding = 16)
{
return new Thickness(padding);
}
// 响应式尺寸
public static bool IsCompact(double width)
{
return width < 180;
}
public static bool IsNormal(double width)
{
return width >= 180 && width < 300;
}
public static bool IsExpanded(double width)
{
return width >= 300;
}
}
```
## ✅ 布局检查清单
发布前请检查:
### 安全区域
- [ ] 上下左右至少 16px 边距
- [ ] 内容不会紧贴边缘
- [ ] 圆角区域没有被裁切
### 间距
- [ ] 使用 4px 基础网格
- [ ] 相关元素间距 8px
- [ ] 区块间距 16px
- [ ] 间距统一一致
### 尺寸
- [ ] 最小宽度 ≥ 120px
- [ ] 最小高度 ≥ 80px
- [ ] 按钮尺寸 ≥ 32×32px
- [ ] 尺寸是 4 的倍数
### 对齐
- [ ] 元素精确对齐
- [ ] 左右边距对称
- [ ] 文字基线对齐
- [ ] 视觉平衡
### 响应式
- [ ] 小尺寸下正常显示
- [ ] 大尺寸下充分利用空间
- [ ] 文本溢出正确处理
- [ ] 图片按比例缩放
## 📖 相关文档
- [视觉规范](02-视觉规范.md) - 颜色、字体、图标
- [交互规范](04-交互规范.md) - 交互状态和动画
- [组件系统](../01-插件开发/02-核心概念/02-组件系统.md) - 组件开发
- [天气组件案例](../01-插件开发/04-实战案例/01-天气组件.md) - 完整示例
---
**记住**: 安全区域 16px间距基于 4px 网格,一切对齐精确。