mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-18 22:46:38 +08:00
11 KiB
11 KiB
OptionButtonGroup 选项按钮组
概述
选项按钮组(OptionButtonGroup)是以按钮样式呈现的单选组件,用于在多个互斥选项中选择一个。它将传统单选按钮的逻辑与按钮的视觉形态相结合,适用于数量有限且语义明确的选项集合,如切换视图模式、选择排序方式、切换布局方向等。
AtomUI 的 OptionButtonGroup 控件对应 Ant Design 5.0 Radio.Group 中 optionType="button" 的变体(即按钮样式的单选组),在 .NET / Avalonia 平台上提供与 Ant Design React 版一致的视觉体验和交互行为。
设计原理
Ant Design 的按钮单选设计哲学
Ant Design 的 Radio.Group 在 optionType="button" 模式下,将每个单选选项渲染为按钮外观。与普通单选按钮(圆形勾选框)相比,按钮样式的单选组更加紧凑、视觉权重更高,适合放置在工具栏或控制面板中。
两种按钮样式:
| 样式 | 设计意图 | 视觉表现 |
|---|---|---|
| 🔲 Outline(轮廓) | 默认样式,选中项通过边框颜色和文字颜色区分 | 选中项边框变为主色(ColorPrimary),文字变为主色 |
| 🔳 Solid(实色) | 更强调选中状态,选中项有实色填充背景 | 选中项背景变为主色填充,文字变为白色 |
三种尺寸(通过 SizeType 控制):
| 尺寸 | 高度 | 说明 |
|---|---|---|
Large |
40px | 大号,醒目场景 |
Middle |
32px | 中号(默认),常规场景 |
Small |
24px | 小号,紧凑布局 |
Avalonia 基础能力
AtomUI 的 OptionButtonGroup 体系基于 Avalonia 的以下基础能力构建:
- OptionButton(
AbstractOptionButton)继承自Avalonia.Controls.RadioButton,获得单选互斥行为、IsChecked状态管理、Content内容呈现等能力 - OptionButtonGroup(
AbstractOptionButtonGroup)继承自SelectingItemsControl,获得ItemsSource数据驱动、SelectedItem/SelectedIndex选中管理、容器化子项(PrepareContainerForItemOverride)等能力
AtomUI 的实现设计
AtomUI 的 OptionButtonGroup 采用跨平台两层继承模型:
| 设计能力 | 实现方式 | 设计动机 |
|---|---|---|
| 两种按钮样式 | OptionButtonStyle 枚举 + 伪类驱动样式 |
对齐 Ant Design 的 buttonStyle(solid / outline) |
| 三种尺寸 | ISizeTypeAware 接口 + SizeType 共享属性 |
全局统一的 Large / Middle / Small 尺寸系统 |
| 自动位置感知 | OptionButtonPositionTrait 枚举 |
自动计算每个按钮的位置(First/Middle/Last/OnlyOne),裁剪圆角 |
| 图标支持 | Icon 属性(PathIcon 类型) |
按钮支持文字 + 图标组合 |
| 选中边框绘制(Outline) | 自定义 Render 方法 |
Outline 模式下选中项绘制主色边框覆盖 |
| 分隔线绘制 | 自定义 Render 方法 |
按钮之间绘制细分隔线 |
| 点击波纹 | IWaveSpiritAwareControl + WaveSpiritDecorator |
复刻 Ant Design 的 Wave 点击涟漪效果 |
| 过渡动画 | IsMotionEnabled + Transitions |
背景色/前景色/边框色平滑过渡 |
| 表单集成 | IFormItemAware 接口 |
可参与 FormItem 验证流程 |
| Design Token | OptionButtonToken + RegisterTokenResourceScope |
所有视觉值从全局/组件级 Token 派生 |
功能详解
按钮样式(OptionButtonStyle)
通过 ButtonStyle 属性设置,影响选中项的视觉表现:
- Outline(默认):选中项使用主色边框 + 主色文字,背景保持透明。Group 容器在选中项位置绘制一个覆盖边框
- Solid:选中项使用主色背景填充 + 白色文字。Solid 模式下相邻选中项之间不绘制分隔线
自动位置感知与圆角裁剪
OptionButtonGroup 自动为每个子按钮分配 GroupPositionTrait:
First:第一个按钮,保留左侧圆角,右侧圆角为 0Middle:中间按钮,四个圆角均为 0Last:最后一个按钮,保留右侧圆角,左侧圆角为 0OnlyOne:唯一按钮,保留全部圆角
分隔线与选中边框
Group 容器的 Render 方法负责绘制:
- 外部统一边框:整个组的外围边框(
BorderBrush+BorderThickness) - 分隔线:每两个相邻按钮之间绘制垂直分隔线
- 选中边框(Outline 模式):在选中按钮的位置绘制
SelectedOptionBorderColor覆盖边框
数据驱动
OptionButtonGroup 支持两种使用方式:
- 声明式子项:直接在 AXAML 中添加
OptionButton子控件 - 数据绑定:通过
ItemsSource绑定OptionButtonData集合,自动生成按钮容器
与 Ant Design 规范的对齐程度
| 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 |
|---|---|---|---|
按钮样式单选 optionType="button" |
✅ | ✅ OptionButtonGroup + OptionButton |
✅ 完全对齐 |
Outline 样式 buttonStyle="outline" |
✅ | ✅ ButtonStyle="Outline" |
✅ 完全对齐 |
Solid 样式 buttonStyle="solid" |
✅ | ✅ ButtonStyle="Solid" |
✅ 完全对齐 |
三种尺寸 size |
✅ large / middle / small |
✅ SizeType |
✅ 完全对齐 |
| 禁用单个选项 | ✅ disabled |
✅ IsEnabled |
✅ 完全对齐 |
| 禁用整个组 | ✅ disabled |
✅ IsEnabled |
✅ 完全对齐 |
选中变更回调 onChange |
✅ 函数 | ✅ OptionCheckedChanged 事件 |
✅ 完全对齐 |
| 图标支持 | ✅ icon (5.x) |
✅ Icon 属性 |
✅ 完全对齐 |
默认选中 defaultValue |
✅ | ✅ OptionButton.IsChecked="True" |
✅ 完全对齐 |
数据驱动 options |
✅ 数组 | ✅ ItemsSource + OptionButtonData |
✅ 完全对齐 |
继承关系
跨平台两层模型
AtomUI.Controls (基础层,设备无关) AtomUI.Desktop.Controls (平台层)
────────────────────────────────── ──────────────────────────────────
AbstractOptionButton : RadioButton ───► OptionButton : AbstractOptionButton
AbstractOptionButtonGroup : SelectingItemsControl ─► OptionButtonGroup : AbstractOptionButtonGroup
AbstractOptionButton(基础层)
Avalonia.Controls.Primitives.TemplatedControl
└── Avalonia.Controls.ContentControl
└── Avalonia.Controls.Primitives.ToggleButton
└── Avalonia.Controls.RadioButton
└── AtomUI.Controls.Commons.AbstractOptionButton
└── AtomUI.Desktop.Controls.OptionButton
AbstractOptionButtonGroup(基础层)
Avalonia.Controls.Primitives.TemplatedControl
└── Avalonia.Controls.ItemsControl
└── Avalonia.Controls.Primitives.SelectingItemsControl
└── AtomUI.Controls.Commons.AbstractOptionButtonGroup
├── implements ISizeTypeAware
├── implements IWaveSpiritAwareControl
├── implements IFormItemAware
└── AtomUI.Desktop.Controls.OptionButtonGroup
各层级职责划分:
| 层级 | 提供的能力 |
|---|---|
RadioButton |
单选互斥行为、IsChecked 状态、Content 内容、GroupName 分组 |
SelectingItemsControl |
ItemsSource 数据驱动、SelectedItem / SelectedIndex、容器化管理 |
AbstractOptionButton |
位置感知圆角裁剪、Icon 图标支持、WaveSpirit 波纹、过渡动画、自定义渲染(边框绘制) |
AbstractOptionButtonGroup |
按钮样式(Outline/Solid)、尺寸传播、分隔线绘制、选中边框绘制、位置分配、OptionCheckedChanged 事件、表单集成 |
OptionButton / OptionButtonGroup |
Desktop Token 注册(OptionButtonToken.ScopeProvider) |
实现的共享接口:
| 接口 | 定义位置 | 作用 |
|---|---|---|
ISizeTypeAware |
AtomUI.Controls.Shared |
支持 SizeType(Small / Middle / Large)三种尺寸切换 |
IWaveSpiritAwareControl |
AtomUI.Controls.Shared |
支持点击涟漪(Wave)动画效果 |
IFormItemAware |
AtomUI.Controls.Shared |
可作为 FormItem 的子控件参与表单验证 |
源码位置
基础层(AtomUI.Controls)
| 文件路径 | 说明 |
|---|---|
src/AtomUI.Controls/OptionButtonGroup/AbstractOptionButton.cs |
设备无关的选项按钮基类 |
src/AtomUI.Controls/OptionButtonGroup/AbstractOptionButtonGroup.cs |
设备无关的选项按钮组基类 |
src/AtomUI.Controls/OptionButtonGroup/OptionButtonGroupEnums.cs |
OptionButtonStyle / OptionButtonPositionTrait 枚举 |
src/AtomUI.Controls/OptionButtonGroup/OptionButtonData.cs |
数据驱动模型 |
src/AtomUI.Controls/OptionButtonGroup/OptionButtonPointerEventArgs.cs |
指针事件参数 |
src/AtomUI.Controls/OptionButtonGroup/OptionCheckedChangedEventArgs.cs |
选中变更事件参数 |
平台层(AtomUI.Desktop.Controls)
| 文件路径 | 说明 |
|---|---|
src/AtomUI.Desktop.Controls/OptionButtonGroup/OptionButton.cs |
桌面端 OptionButton |
src/AtomUI.Desktop.Controls/OptionButtonGroup/OptionButtonGroup.cs |
桌面端 OptionButtonGroup |
src/AtomUI.Desktop.Controls/OptionButtonGroup/OptionButtonToken.cs |
组件级 Design Token |
src/AtomUI.Desktop.Controls/OptionButtonGroup/Themes/OptionButtonTheme.axaml |
OptionButton 主题 |
src/AtomUI.Desktop.Controls/OptionButtonGroup/Themes/OptionButtonGroupTheme.axaml |
OptionButtonGroup 主题 |
src/AtomUI.Desktop.Controls/OptionButtonGroup/Themes/OptionButtonBoxThemes.axaml |
主题汇总注册 |
Gallery 示例
| 文件路径 | 说明 |
|---|---|
controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/RadioButtonShowCase.axaml |
RadioButton 与 OptionButton 综合范例 |
模板结构
OptionButton 模板
Panel
├── WaveSpiritDecorator (PART_WaveSpirit) ← 点击波纹效果层
└── DockPanel#ContentLayout ← 内容布局
├── IconPresenter#IconPresenter ← 图标(DockPanel.Dock="Left",可选)
└── TextBlock ← 文本内容
OptionButtonGroup 模板
Border#Frame ← 外围容器(边框+圆角)
└── ItemsPresenter (PART_ItemsPresenter) ← 子项呈现器
└── StackPanel (Horizontal) ← 默认水平排列面板
├── OptionButton ← 选项按钮 1
├── OptionButton ← 选项按钮 2
└── ...
布局设计要点:
- 自定义渲染:OptionButtonGroup 的
Render方法负责绘制外围边框、分隔线和选中边框覆盖,而非依赖模板中的多层 Border - 圆角自动裁剪:每个 OptionButton 根据在组中的位置自动计算圆角(仅首尾按钮保留外侧圆角)
- 分隔线绘制:使用
DrawLine在相邻按钮间绘制像素对齐的分隔线(EdgeMode.Aliased)