mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
802 lines
20 KiB
Markdown
802 lines
20 KiB
Markdown
|
|
# 交互规范
|
|||
|
|
|
|||
|
|
本文档详细说明组件交互设计规范,包括交互状态、动画过渡、反馈机制和拖拽调整。
|
|||
|
|
|
|||
|
|
## 🎯 交互设计原则
|
|||
|
|
|
|||
|
|
- **即时反馈** - 所有操作都应有立即的视觉反馈
|
|||
|
|
- **清晰可预测** - 用户能预期操作的结果
|
|||
|
|
- **流畅自然** - 动画和过渡平滑流畅
|
|||
|
|
- **符合直觉** - 遵循用户的使用习惯
|
|||
|
|
- **宽容错误** - 允许撤销和恢复
|
|||
|
|
|
|||
|
|
## 🖱️ 交互状态
|
|||
|
|
|
|||
|
|
### 标准交互状态
|
|||
|
|
|
|||
|
|
所有可交互元素都应该有以下状态:
|
|||
|
|
|
|||
|
|
| 状态 | 说明 | 视觉表现 |
|
|||
|
|
|-----|------|---------|
|
|||
|
|
| **正常(Normal)** | 默认状态 | 标准样式 |
|
|||
|
|
| **悬停(Hover)** | 鼠标悬停 | 背景变化、光标变化 |
|
|||
|
|
| **按下(Pressed)** | 鼠标按下 | 背景更暗、轻微缩放 |
|
|||
|
|
| **聚焦(Focused)** | 键盘聚焦 | 显示聚焦环 |
|
|||
|
|
| **禁用(Disabled)** | 不可用 | 降低透明度、灰色显示 |
|
|||
|
|
| **选中(Selected)** | 被选中 | 强调色背景 |
|
|||
|
|
|
|||
|
|
### 按钮状态
|
|||
|
|
|
|||
|
|
#### 主要按钮(Primary Button)
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Button Content="确定"
|
|||
|
|
Padding="12,6"
|
|||
|
|
Background="{DynamicResource AccentBrush}"
|
|||
|
|
Foreground="White">
|
|||
|
|
|
|||
|
|
<Button.Styles>
|
|||
|
|
<!-- 悬停状态 -->
|
|||
|
|
<Style Selector="Button:pointerover">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<Animation Duration="0:0:0.15" Easing="CubicEaseOut">
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="Background"
|
|||
|
|
Value="{DynamicResource AccentHoverBrush}"/>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
|
|||
|
|
<!-- 按下状态 -->
|
|||
|
|
<Style Selector="Button:pressed">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<Animation Duration="0:0:0.1" Easing="CubicEaseOut">
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="Background"
|
|||
|
|
Value="{DynamicResource AccentPressedBrush}"/>
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<ScaleTransform ScaleX="0.98" ScaleY="0.98"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
|
|||
|
|
<!-- 禁用状态 -->
|
|||
|
|
<Style Selector="Button:disabled">
|
|||
|
|
<Setter Property="Opacity" Value="0.5"/>
|
|||
|
|
</Style>
|
|||
|
|
|
|||
|
|
</Button.Styles>
|
|||
|
|
|
|||
|
|
</Button>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 次要按钮(Secondary Button)
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Button Content="取消"
|
|||
|
|
Padding="12,6"
|
|||
|
|
Background="{DynamicResource CardBackgroundSecondaryBrush}"
|
|||
|
|
Foreground="{DynamicResource TextFillColorPrimaryBrush}">
|
|||
|
|
|
|||
|
|
<Button.Styles>
|
|||
|
|
<!-- 悬停状态 -->
|
|||
|
|
<Style Selector="Button:pointerover">
|
|||
|
|
<Setter Property="Background" Value="#EBEBEB"/>
|
|||
|
|
</Style>
|
|||
|
|
|
|||
|
|
<!-- 按下状态 -->
|
|||
|
|
<Style Selector="Button:pressed">
|
|||
|
|
<Setter Property="Background" Value="#E0E0E0"/>
|
|||
|
|
</Style>
|
|||
|
|
</Button.Styles>
|
|||
|
|
|
|||
|
|
</Button>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 图标按钮
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Button Padding="8"
|
|||
|
|
Background="Transparent"
|
|||
|
|
BorderThickness="0">
|
|||
|
|
<TextBlock Text="🔄" FontSize="16"/>
|
|||
|
|
|
|||
|
|
<Button.Styles>
|
|||
|
|
<!-- 悬停状态 -->
|
|||
|
|
<Style Selector="Button:pointerover">
|
|||
|
|
<Setter Property="Background"
|
|||
|
|
Value="{DynamicResource CardBackgroundSecondaryBrush}"/>
|
|||
|
|
</Style>
|
|||
|
|
|
|||
|
|
<!-- 按下状态 -->
|
|||
|
|
<Style Selector="Button:pressed">
|
|||
|
|
<Setter Property="Background" Value="#E0E0E0"/>
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<ScaleTransform ScaleX="0.95" ScaleY="0.95"/>
|
|||
|
|
</Setter>
|
|||
|
|
</Style>
|
|||
|
|
</Button.Styles>
|
|||
|
|
|
|||
|
|
</Button>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 输入框状态
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<TextBox Text="{Binding InputText}"
|
|||
|
|
Watermark="请输入内容..."
|
|||
|
|
Padding="8"
|
|||
|
|
BorderBrush="{DynamicResource TextBoxBorderBrush}"
|
|||
|
|
BorderThickness="1">
|
|||
|
|
|
|||
|
|
<TextBox.Styles>
|
|||
|
|
<!-- 聚焦状态 -->
|
|||
|
|
<Style Selector="TextBox:focus">
|
|||
|
|
<Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}"/>
|
|||
|
|
<Setter Property="BorderThickness" Value="2"/>
|
|||
|
|
</Style>
|
|||
|
|
|
|||
|
|
<!-- 错误状态 -->
|
|||
|
|
<Style Selector="TextBox.error">
|
|||
|
|
<Setter Property="BorderBrush" Value="{DynamicResource ErrorBrush}"/>
|
|||
|
|
<Setter Property="BorderThickness" Value="2"/>
|
|||
|
|
</Style>
|
|||
|
|
|
|||
|
|
<!-- 禁用状态 -->
|
|||
|
|
<Style Selector="TextBox:disabled">
|
|||
|
|
<Setter Property="Opacity" Value="0.5"/>
|
|||
|
|
<Setter Property="Background" Value="{DynamicResource CardBackgroundSecondaryBrush}"/>
|
|||
|
|
</Style>
|
|||
|
|
</TextBox.Styles>
|
|||
|
|
|
|||
|
|
</TextBox>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 光标样式
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<!-- 可点击元素 -->
|
|||
|
|
<Button Cursor="Hand">点击我</Button>
|
|||
|
|
|
|||
|
|
<!-- 文本输入 -->
|
|||
|
|
<TextBox Cursor="IBeam"/>
|
|||
|
|
|
|||
|
|
<!-- 拖拽元素 -->
|
|||
|
|
<Border Cursor="SizeAll">拖动我</Border>
|
|||
|
|
|
|||
|
|
<!-- 调整大小 -->
|
|||
|
|
<Border Cursor="SizeNWSE">调整大小</Border>
|
|||
|
|
|
|||
|
|
<!-- 禁用元素 -->
|
|||
|
|
<Button IsEnabled="False" Cursor="No">禁用</Button>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎬 动画与过渡
|
|||
|
|
|
|||
|
|
### 动画时长标准
|
|||
|
|
|
|||
|
|
| 类型 | 时长 | 使用场景 |
|
|||
|
|
|-----|------|---------|
|
|||
|
|
| **微交互** | 100-150ms | 悬停、点击 |
|
|||
|
|
| **短动画** | 200-300ms | 展开、收起 |
|
|||
|
|
| **中动画** | 300-500ms | 页面切换、弹出 |
|
|||
|
|
| **长动画** | 500-800ms | 复杂过渡 |
|
|||
|
|
|
|||
|
|
### 缓动函数(Easing)
|
|||
|
|
|
|||
|
|
| 函数 | 效果 | 使用场景 |
|
|||
|
|
|-----|------|---------|
|
|||
|
|
| **Linear** | 线性 | 加载动画、循环动画 |
|
|||
|
|
| **CubicEaseOut** | 快进慢出 | 大部分交互动画 |
|
|||
|
|
| **CubicEaseIn** | 慢进快出 | 元素退出 |
|
|||
|
|
| **CubicEaseInOut** | 慢进慢出 | 平滑过渡 |
|
|||
|
|
| **BackEaseOut** | 回弹效果 | 强调动画 |
|
|||
|
|
| **ElasticEaseOut** | 弹性效果 | 有趣的交互 |
|
|||
|
|
|
|||
|
|
### 悬停动画
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Border Background="{DynamicResource CardBackgroundBrush}"
|
|||
|
|
CornerRadius="8"
|
|||
|
|
Padding="16">
|
|||
|
|
|
|||
|
|
<Border.Styles>
|
|||
|
|
<Style Selector="Border:pointerover">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<!-- 背景色过渡 -->
|
|||
|
|
<Animation Duration="0:0:0.15" Easing="CubicEaseOut">
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="Background"
|
|||
|
|
Value="{DynamicResource CardBackgroundSecondaryBrush}"/>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
|
|||
|
|
<!-- 阴影过渡 -->
|
|||
|
|
<Animation Duration="0:0:0.15" Easing="CubicEaseOut">
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="BoxShadow" Value="0 4 16 0 #26000000"/>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
|
|||
|
|
<!-- 轻微上移 -->
|
|||
|
|
<Animation Duration="0:0:0.15" Easing="CubicEaseOut">
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<TranslateTransform Y="-2"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
</Border.Styles>
|
|||
|
|
|
|||
|
|
</Border>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 点击动画
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Button Content="点击我" Padding="12,6">
|
|||
|
|
<Button.Styles>
|
|||
|
|
<Style Selector="Button:pressed">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<!-- 缩放动画 -->
|
|||
|
|
<Animation Duration="0:0:0.1" Easing="CubicEaseOut">
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<ScaleTransform ScaleX="0.95" ScaleY="0.95"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
</Button.Styles>
|
|||
|
|
</Button>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 展开/收起动画
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Expander Header="点击展开" IsExpanded="{Binding IsExpanded}">
|
|||
|
|
<Expander.ContentTransition>
|
|||
|
|
<CrossFade Duration="0:0:0.3"/>
|
|||
|
|
</Expander.ContentTransition>
|
|||
|
|
|
|||
|
|
<Border Padding="16">
|
|||
|
|
<TextBlock Text="展开的内容" TextWrapping="Wrap"/>
|
|||
|
|
</Border>
|
|||
|
|
</Expander>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 淡入/淡出动画
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<!-- 元素淡入 -->
|
|||
|
|
<Border Opacity="0">
|
|||
|
|
<Border.Transitions>
|
|||
|
|
<Transitions>
|
|||
|
|
<DoubleTransition Property="Opacity" Duration="0:0:0.3"/>
|
|||
|
|
</Transitions>
|
|||
|
|
</Border.Transitions>
|
|||
|
|
|
|||
|
|
<Border.Loaded>
|
|||
|
|
<EventTrigger>
|
|||
|
|
<ChangePropertyAction TargetName="Self" Property="Opacity" Value="1"/>
|
|||
|
|
</EventTrigger>
|
|||
|
|
</Border.Loaded>
|
|||
|
|
</Border>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 旋转动画(加载中)
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<TextBlock Text="⏳" FontSize="24">
|
|||
|
|
<TextBlock.RenderTransform>
|
|||
|
|
<RotateTransform/>
|
|||
|
|
</TextBlock.RenderTransform>
|
|||
|
|
|
|||
|
|
<TextBlock.Styles>
|
|||
|
|
<Style Selector="TextBlock">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<Animation Duration="0:0:1" IterationCount="Infinite">
|
|||
|
|
<KeyFrame Cue="0%">
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<RotateTransform Angle="0"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<RotateTransform Angle="360"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
</TextBlock.Styles>
|
|||
|
|
</TextBlock>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 脉冲动画(加载中)
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Border Background="{DynamicResource AccentBrush}"
|
|||
|
|
Width="40" Height="40"
|
|||
|
|
CornerRadius="20">
|
|||
|
|
|
|||
|
|
<Border.Styles>
|
|||
|
|
<Style Selector="Border">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<Animation Duration="0:0:1.5"
|
|||
|
|
IterationCount="Infinite"
|
|||
|
|
Easing="CubicEaseInOut">
|
|||
|
|
<KeyFrame Cue="0%">
|
|||
|
|
<Setter Property="Opacity" Value="1"/>
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<ScaleTransform ScaleX="1" ScaleY="1"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
<KeyFrame Cue="50%">
|
|||
|
|
<Setter Property="Opacity" Value="0.5"/>
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<ScaleTransform ScaleX="0.8" ScaleY="0.8"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="Opacity" Value="1"/>
|
|||
|
|
<Setter Property="RenderTransform">
|
|||
|
|
<ScaleTransform ScaleX="1" ScaleY="1"/>
|
|||
|
|
</Setter>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
</Border.Styles>
|
|||
|
|
|
|||
|
|
</Border>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 💬 反馈机制
|
|||
|
|
|
|||
|
|
### 加载状态
|
|||
|
|
|
|||
|
|
#### 加载指示器
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<!-- 旋转加载 -->
|
|||
|
|
<StackPanel Spacing="8"
|
|||
|
|
HorizontalAlignment="Center"
|
|||
|
|
VerticalAlignment="Center">
|
|||
|
|
<TextBlock Text="⏳" FontSize="32">
|
|||
|
|
<!-- 旋转动画(见上文) -->
|
|||
|
|
</TextBlock>
|
|||
|
|
<TextBlock Text="加载中..."
|
|||
|
|
FontSize="14"
|
|||
|
|
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
|||
|
|
</StackPanel>
|
|||
|
|
|
|||
|
|
<!-- 进度条 -->
|
|||
|
|
<ProgressBar Value="{Binding Progress}"
|
|||
|
|
Minimum="0"
|
|||
|
|
Maximum="100"
|
|||
|
|
Height="4"
|
|||
|
|
Foreground="{DynamicResource AccentBrush}"/>
|
|||
|
|
|
|||
|
|
<!-- 不确定进度 -->
|
|||
|
|
<ProgressBar IsIndeterminate="True"
|
|||
|
|
Height="4"
|
|||
|
|
Foreground="{DynamicResource AccentBrush}"/>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 骨架屏
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<StackPanel Spacing="8">
|
|||
|
|
<!-- 标题骨架 -->
|
|||
|
|
<Border Width="120" Height="20"
|
|||
|
|
Background="#F0F0F0"
|
|||
|
|
CornerRadius="4"/>
|
|||
|
|
|
|||
|
|
<!-- 内容骨架 -->
|
|||
|
|
<Border Width="200" Height="16"
|
|||
|
|
Background="#F0F0F0"
|
|||
|
|
CornerRadius="4"/>
|
|||
|
|
<Border Width="180" Height="16"
|
|||
|
|
Background="#F0F0F0"
|
|||
|
|
CornerRadius="4"/>
|
|||
|
|
|
|||
|
|
<!-- 添加脉冲动画 -->
|
|||
|
|
<Border.Styles>
|
|||
|
|
<Style Selector="Border">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<Animation Duration="0:0:1.5"
|
|||
|
|
IterationCount="Infinite"
|
|||
|
|
Easing="CubicEaseInOut">
|
|||
|
|
<KeyFrame Cue="0%">
|
|||
|
|
<Setter Property="Opacity" Value="1"/>
|
|||
|
|
</KeyFrame>
|
|||
|
|
<KeyFrame Cue="50%">
|
|||
|
|
<Setter Property="Opacity" Value="0.5"/>
|
|||
|
|
</KeyFrame>
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="Opacity" Value="1"/>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
</Border.Styles>
|
|||
|
|
</StackPanel>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 错误状态
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Border Background="{DynamicResource CardBackgroundBrush}"
|
|||
|
|
BorderBrush="{DynamicResource ErrorBrush}"
|
|||
|
|
BorderThickness="2"
|
|||
|
|
CornerRadius="8"
|
|||
|
|
Padding="16">
|
|||
|
|
|
|||
|
|
<StackPanel Spacing="12">
|
|||
|
|
<!-- 错误图标 -->
|
|||
|
|
<TextBlock Text="❌"
|
|||
|
|
FontSize="32"
|
|||
|
|
HorizontalAlignment="Center"/>
|
|||
|
|
|
|||
|
|
<!-- 错误信息 -->
|
|||
|
|
<TextBlock Text="加载失败"
|
|||
|
|
FontSize="16"
|
|||
|
|
FontWeight="SemiBold"
|
|||
|
|
HorizontalAlignment="Center"
|
|||
|
|
Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
|||
|
|
|
|||
|
|
<TextBlock Text="网络连接失败,请检查网络设置"
|
|||
|
|
FontSize="14"
|
|||
|
|
TextWrapping="Wrap"
|
|||
|
|
HorizontalAlignment="Center"
|
|||
|
|
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
|||
|
|
|
|||
|
|
<!-- 重试按钮 -->
|
|||
|
|
<Button Content="重试"
|
|||
|
|
Command="{Binding RetryCommand}"
|
|||
|
|
HorizontalAlignment="Center"
|
|||
|
|
Padding="16,6"
|
|||
|
|
Background="{DynamicResource AccentBrush}"
|
|||
|
|
Foreground="White"/>
|
|||
|
|
</StackPanel>
|
|||
|
|
|
|||
|
|
</Border>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 空状态
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<StackPanel Spacing="16"
|
|||
|
|
HorizontalAlignment="Center"
|
|||
|
|
VerticalAlignment="Center">
|
|||
|
|
|
|||
|
|
<!-- 空状态图标 -->
|
|||
|
|
<TextBlock Text="📭"
|
|||
|
|
FontSize="48"
|
|||
|
|
HorizontalAlignment="Center"/>
|
|||
|
|
|
|||
|
|
<!-- 空状态文字 -->
|
|||
|
|
<StackPanel Spacing="8">
|
|||
|
|
<TextBlock Text="暂无数据"
|
|||
|
|
FontSize="16"
|
|||
|
|
FontWeight="SemiBold"
|
|||
|
|
HorizontalAlignment="Center"
|
|||
|
|
Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
|||
|
|
|
|||
|
|
<TextBlock Text="添加第一个项目开始使用"
|
|||
|
|
FontSize="14"
|
|||
|
|
HorizontalAlignment="Center"
|
|||
|
|
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
|||
|
|
</StackPanel>
|
|||
|
|
|
|||
|
|
<!-- 操作按钮 -->
|
|||
|
|
<Button Content="添加项目"
|
|||
|
|
Command="{Binding AddCommand}"
|
|||
|
|
Padding="16,6"
|
|||
|
|
Background="{DynamicResource AccentBrush}"
|
|||
|
|
Foreground="White"/>
|
|||
|
|
|
|||
|
|
</StackPanel>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 成功反馈
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<!-- 简短通知(Toast) -->
|
|||
|
|
<Border Background="{DynamicResource SuccessBrush}"
|
|||
|
|
CornerRadius="8"
|
|||
|
|
Padding="12,8"
|
|||
|
|
BoxShadow="0 4 16 0 #26000000">
|
|||
|
|
|
|||
|
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
|||
|
|
<TextBlock Text="✅" FontSize="16"/>
|
|||
|
|
<TextBlock Text="操作成功"
|
|||
|
|
FontSize="14"
|
|||
|
|
Foreground="White"/>
|
|||
|
|
</StackPanel>
|
|||
|
|
|
|||
|
|
<!-- 自动淡出动画 -->
|
|||
|
|
<Border.Styles>
|
|||
|
|
<Style Selector="Border">
|
|||
|
|
<Style.Animations>
|
|||
|
|
<Animation Duration="0:0:0.3" Delay="0:0:2" FillMode="Forward">
|
|||
|
|
<KeyFrame Cue="100%">
|
|||
|
|
<Setter Property="Opacity" Value="0"/>
|
|||
|
|
</KeyFrame>
|
|||
|
|
</Animation>
|
|||
|
|
</Style.Animations>
|
|||
|
|
</Style>
|
|||
|
|
</Border.Styles>
|
|||
|
|
|
|||
|
|
</Border>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 提示信息(Tooltip)
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Button Content="🔄"
|
|||
|
|
Padding="8"
|
|||
|
|
ToolTip.Tip="刷新数据"
|
|||
|
|
ToolTip.ShowDelay="500">
|
|||
|
|
<!-- 按钮内容 -->
|
|||
|
|
</Button>
|
|||
|
|
|
|||
|
|
<!-- 自定义 Tooltip -->
|
|||
|
|
<Button Content="⚙️" Padding="8">
|
|||
|
|
<ToolTip.Tip>
|
|||
|
|
<Border Background="{DynamicResource CardBackgroundBrush}"
|
|||
|
|
BorderBrush="{DynamicResource CardBorderBrush}"
|
|||
|
|
BorderThickness="1"
|
|||
|
|
CornerRadius="4"
|
|||
|
|
Padding="8"
|
|||
|
|
BoxShadow="0 2 8 0 #1A000000">
|
|||
|
|
<StackPanel Spacing="4">
|
|||
|
|
<TextBlock Text="设置"
|
|||
|
|
FontSize="14"
|
|||
|
|
FontWeight="SemiBold"/>
|
|||
|
|
<TextBlock Text="打开组件设置"
|
|||
|
|
FontSize="12"
|
|||
|
|
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
|||
|
|
</StackPanel>
|
|||
|
|
</Border>
|
|||
|
|
</ToolTip.Tip>
|
|||
|
|
</Button>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🖐️ 拖拽与调整
|
|||
|
|
|
|||
|
|
### 拖拽组件
|
|||
|
|
|
|||
|
|
组件应支持拖拽移动:
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
public class DraggableComponent : ComponentBase
|
|||
|
|
{
|
|||
|
|
private Point _dragStartPoint;
|
|||
|
|
private bool _isDragging;
|
|||
|
|
|
|||
|
|
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
|||
|
|
{
|
|||
|
|
_dragStartPoint = e.GetPosition(this);
|
|||
|
|
_isDragging = true;
|
|||
|
|
Cursor = new Cursor(StandardCursorType.SizeAll);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnPointerMoved(PointerEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (_isDragging)
|
|||
|
|
{
|
|||
|
|
var currentPosition = e.GetPosition(this.Parent as Visual);
|
|||
|
|
var offset = currentPosition - _dragStartPoint;
|
|||
|
|
|
|||
|
|
// 更新位置
|
|||
|
|
Canvas.SetLeft(this, Canvas.GetLeft(this) + offset.X);
|
|||
|
|
Canvas.SetTop(this, Canvas.GetTop(this) + offset.Y);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
|||
|
|
{
|
|||
|
|
_isDragging = false;
|
|||
|
|
Cursor = new Cursor(StandardCursorType.Arrow);
|
|||
|
|
|
|||
|
|
// 保存位置
|
|||
|
|
SavePosition();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 调整大小
|
|||
|
|
|
|||
|
|
组件应支持调整尺寸:
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<Border Width="{Binding Width}"
|
|||
|
|
Height="{Binding Height}"
|
|||
|
|
Background="{DynamicResource CardBackgroundBrush}">
|
|||
|
|
|
|||
|
|
<!-- 组件内容 -->
|
|||
|
|
<Grid>
|
|||
|
|
<!-- ... -->
|
|||
|
|
</Grid>
|
|||
|
|
|
|||
|
|
<!-- 调整大小手柄 -->
|
|||
|
|
<Grid>
|
|||
|
|
<!-- 右下角手柄 -->
|
|||
|
|
<Border Width="12" Height="12"
|
|||
|
|
Background="{DynamicResource AccentBrush}"
|
|||
|
|
CornerRadius="6"
|
|||
|
|
HorizontalAlignment="Right"
|
|||
|
|
VerticalAlignment="Bottom"
|
|||
|
|
Cursor="SizeNWSE"
|
|||
|
|
PointerPressed="OnResizeHandlePressed"
|
|||
|
|
PointerMoved="OnResizeHandleMoved"
|
|||
|
|
PointerReleased="OnResizeHandleReleased"/>
|
|||
|
|
</Grid>
|
|||
|
|
|
|||
|
|
</Border>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
private void OnResizeHandlePressed(object sender, PointerPressedEventArgs e)
|
|||
|
|
{
|
|||
|
|
_isResizing = true;
|
|||
|
|
_resizeStartPoint = e.GetPosition(this.Parent as Visual);
|
|||
|
|
_initialWidth = Width;
|
|||
|
|
_initialHeight = Height;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnResizeHandleMoved(object sender, PointerEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (_isResizing)
|
|||
|
|
{
|
|||
|
|
var currentPoint = e.GetPosition(this.Parent as Visual);
|
|||
|
|
var delta = currentPoint - _resizeStartPoint;
|
|||
|
|
|
|||
|
|
Width = Math.Max(MinWidth, _initialWidth + delta.X);
|
|||
|
|
Height = Math.Max(MinHeight, _initialHeight + delta.Y);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnResizeHandleReleased(object sender, PointerReleasedEventArgs e)
|
|||
|
|
{
|
|||
|
|
_isResizing = false;
|
|||
|
|
SaveSize();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 拖拽反馈
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<!-- 拖拽时显示阴影 -->
|
|||
|
|
<Border.Styles>
|
|||
|
|
<Style Selector="Border.dragging">
|
|||
|
|
<Setter Property="BoxShadow" Value="0 8 24 0 #33000000"/>
|
|||
|
|
<Setter Property="Opacity" Value="0.8"/>
|
|||
|
|
</Style>
|
|||
|
|
</Border.Styles>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## ⌨️ 键盘交互
|
|||
|
|
|
|||
|
|
### 快捷键
|
|||
|
|
|
|||
|
|
常用快捷键:
|
|||
|
|
|
|||
|
|
| 快捷键 | 操作 |
|
|||
|
|
|-------|------|
|
|||
|
|
| **Enter** | 确认、提交 |
|
|||
|
|
| **Esc** | 取消、关闭 |
|
|||
|
|
| **Tab** | 焦点切换 |
|
|||
|
|
| **Space** | 激活按钮 |
|
|||
|
|
| **方向键** | 导航、选择 |
|
|||
|
|
| **Ctrl+S** | 保存 |
|
|||
|
|
| **Ctrl+Z** | 撤销 |
|
|||
|
|
| **Ctrl+Y** | 重做 |
|
|||
|
|
|
|||
|
|
### 实现快捷键
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
protected override void OnKeyDown(KeyEventArgs e)
|
|||
|
|
{
|
|||
|
|
switch (e.Key)
|
|||
|
|
{
|
|||
|
|
case Key.Enter:
|
|||
|
|
ConfirmAction();
|
|||
|
|
e.Handled = true;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case Key.Escape:
|
|||
|
|
CancelAction();
|
|||
|
|
e.Handled = true;
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case Key.S when e.KeyModifiers.HasFlag(KeyModifiers.Control):
|
|||
|
|
SaveAction();
|
|||
|
|
e.Handled = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
base.OnKeyDown(e);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 焦点管理
|
|||
|
|
|
|||
|
|
```xml
|
|||
|
|
<!-- 设置初始焦点 -->
|
|||
|
|
<TextBox Name="UsernameBox"
|
|||
|
|
Text="{Binding Username}"
|
|||
|
|
Loaded="OnLoaded"/>
|
|||
|
|
|
|||
|
|
<!-- 代码设置焦点 -->
|
|||
|
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
|||
|
|
{
|
|||
|
|
UsernameBox.Focus();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
<!-- Tab 顺序 -->
|
|||
|
|
<StackPanel>
|
|||
|
|
<TextBox TabIndex="1"/>
|
|||
|
|
<TextBox TabIndex="2"/>
|
|||
|
|
<Button TabIndex="3"/>
|
|||
|
|
</StackPanel>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## ✅ 交互检查清单
|
|||
|
|
|
|||
|
|
发布前请检查:
|
|||
|
|
|
|||
|
|
### 状态反馈
|
|||
|
|
- [ ] 所有按钮有悬停状态
|
|||
|
|
- [ ] 所有按钮有按下状态
|
|||
|
|
- [ ] 禁用状态清晰可见
|
|||
|
|
- [ ] 加载状态有明确提示
|
|||
|
|
- [ ] 错误状态有友好说明
|
|||
|
|
|
|||
|
|
### 动画
|
|||
|
|
- [ ] 动画流畅不卡顿
|
|||
|
|
- [ ] 动画时长合适(100-500ms)
|
|||
|
|
- [ ] 使用合适的缓动函数
|
|||
|
|
- [ ] 不影响性能
|
|||
|
|
- [ ] 可以禁用动画
|
|||
|
|
|
|||
|
|
### 反馈
|
|||
|
|
- [ ] 操作成功有提示
|
|||
|
|
- [ ] 操作失败有说明
|
|||
|
|
- [ ] 空状态有引导
|
|||
|
|
- [ ] 加载中有指示
|
|||
|
|
- [ ] 提示信息清晰
|
|||
|
|
|
|||
|
|
### 拖拽与调整
|
|||
|
|
- [ ] 组件可拖拽移动
|
|||
|
|
- [ ] 组件可调整大小
|
|||
|
|
- [ ] 拖拽有视觉反馈
|
|||
|
|
- [ ] 调整大小有限制
|
|||
|
|
- [ ] 位置和尺寸可保存
|
|||
|
|
|
|||
|
|
### 键盘交互
|
|||
|
|
- [ ] Tab 键可切换焦点
|
|||
|
|
- [ ] Enter 键可确认操作
|
|||
|
|
- [ ] Esc 键可取消操作
|
|||
|
|
- [ ] 快捷键正常工作
|
|||
|
|
- [ ] 焦点状态清晰可见
|
|||
|
|
|
|||
|
|
## 📖 相关文档
|
|||
|
|
|
|||
|
|
- [布局规范](03-布局规范.md) - 安全区域和间距
|
|||
|
|
- [视觉规范](02-视觉规范.md) - 颜色、字体、图标
|
|||
|
|
- [主题系统](05-主题系统.md) - 主题切换实现
|
|||
|
|
- [组件系统](../01-插件开发/02-核心概念/02-组件系统.md) - 组件开发
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**记住**: 即时反馈、流畅动画、清晰提示、直觉交互。
|