- UI组件
- 桌面应用
【免费下载链接】SukiUI
UI Theme for AvaloniaUI
导读
SettingsLayout是 SukiUI(面向 AvaloniaUI 的 UI 主题库)提供的一个专用于「设置页」场景的响应式布局控件:它将一组带标题的设置分组(SettingsLayoutItem)展示为左侧导航摘要 + 右侧内容区的经典设置页形态,并会随窗口宽度自动在「双栏模式」与「单栏堆叠模式」之间切换。读完本文,你将掌握如何用 XAML 声明式地搭建分组设置页面、理解其响应式阈值与摘要栏宽度等关键参数,并能基于源码了解它内部的自适应与平滑滚动机制,直接复用到自己的 Avalonia 项目中。
一、SettingsLayout 是什么
SettingsLayout定义在 SukiUI/Controls/Settings/SettingsLayout.axaml.cs,是一个继承自UserControl的布局容器控件。它的设计目标非常明确:把「设置」这一高频界面形态封装成一个开箱即用的控件,并让它随窗口宽度自动调整布局。
其核心特征可以概括为三点:
- 分组内容展示:通过
Items集合承载任意数量的SettingsLayoutItem,每个SettingsLayoutItem都有独立的Header(标题)与Content(任意控件内容),对应设置页里的一个分组。 - 左侧摘要导航:每个分组的标题会同时以
RadioButton(样式类MenuChip)的形式出现在左侧摘要栏中,点击即可平滑滚动定位到对应分组。 - 响应式自适应:当容器宽度低于阈值时,左侧摘要栏会自动收起(宽度动画过渡到 0),整个页面退化为单一内容列的堆叠形态;宽度恢复后摘要栏再次展开。
从模板结构(SettingsLayout.axaml)可以看到它的内部骨架是一个DockPanel:
<DockPanel MaxWidth="1400" SizeChanged="DockPanel_SizeChanged"> <StackPanel Name="StackSummary" ... DockPanel.Dock="Left" /> <ScrollViewer Name="MyScroll" Classes="Stack"> <StackPanel Name="StackItems" ... /> </ScrollViewer> </DockPanel>其中StackSummary是左侧摘要导航栏,MyScroll/StackItems是右侧内容滚动区(StackPanelExtensions.AnimatedScroll为其启用平滑滚动)。也就是说,整个控件在运行期会由代码动态地把Items渲染成这两部分。
二、快速上手:最小可用示例
原文档给出的最小示例非常直接:在SettingsLayout的Items中放一个ObservableCollection<SettingsLayoutItem>,每个SettingsLayoutItem用Header定义标题、用Content定义分组内容:
<suki:SettingsLayout> <suki:SettingsLayout.Items> <objectModel:ObservableCollection x:TypeArguments="suki:SettingsLayoutItem"> <suki:SettingsLayoutItem Header="Settings Part1"> <suki:SettingsLayoutItem.Content> <Border Background="LightGray" Height="300" /> </suki:SettingsLayoutItem.Content> </suki:SettingsLayoutItem> <suki:SettingsLayoutItem Header="Settings Part 2"> <suki:SettingsLayoutItem.Content> <Border Background="LightGray" Height="300" /> </suki:SettingsLayoutItem.Content> </suki:SettingsLayoutItem> <suki:SettingsLayoutItem Header="Settings Part 3"> <suki:SettingsLayoutItem.Content> <Border Background="LightGray" Height="300" /> </suki:SettingsLayoutItem.Content> </suki:SettingsLayoutItem> </objectModel:ObservableCollection> </suki:SettingsLayout.Items> </suki:SettingsLayout>要点说明:
- 使用前需在 XAML 根节点声明命名空间
xmlns:suki="https://github.com/kikipoulet/SukiUI"与xmlns:objectModel="clr-namespace:System.Collections.ObjectModel;assembly=System.Collections"(示例中objectModel:ObservableCollection即System.Collections.ObjectModel.ObservableCollection<T>)。 - 每个
SettingsLayoutItem.Content可放置任意 Avalonia 控件(Border、StackPanel、GlassCard、ItemsControl等),因此完全可以用原生 XAML 组合出复杂设置表单。 ObservableCollection的增删会被控件监听:SettingsLayout在源码中通过AttachItemsCollection()把Items转型为INotifyCollectionChanged并订阅CollectionChanged事件,集合变化时自动调用UpdateItems()重建界面(见 SettingsLayout.axaml.cs)。也就是说,运行时动态增删设置分组也会被实时反映。
三、把设置分组放进资源:ItemsSource 绑定写法
除了直接在Items内联集合,更符合 MVVM 习惯的做法是把SettingsLayoutItem集合放进UserControl.Resources作为静态资源,再通过Items="{StaticResource ...}"绑定。SukiUI 官方 Demo 的主题设置页正是这样组织的,参见 SukiUI.Demo/Features/Theming/ThemingView.axaml:
<UserControl.Resources> <generic:List x:Key="Collection" x:TypeArguments="suki:SettingsLayoutItem"> <suki:SettingsLayoutItem Header="Base Theme"> <suki:SettingsLayoutItem.Content> <StackPanel Orientation="Horizontal" Spacing="20"> <!-- 亮色/暗色主题切换的 RadioButton 卡片 --> </StackPanel> </suki:SettingsLayoutItem.Content> </suki:SettingsLayoutItem> <suki:SettingsLayoutItem Header="Color Theme"> <suki:SettingsLayoutItem.Content> <ItemsControl ItemsSource="{Binding AvailableColors}"> <!-- 色板选择 --> </ItemsControl> </suki:SettingsLayoutItem.Content> </suki:SettingsLayoutItem> <suki:SettingsLayoutItem Header="Background"> <suki:SettingsLayoutItem.Content> <StackPanel> <!-- 背景动画、过渡与自定义 Shader 开关 --> </StackPanel> </suki:SettingsLayoutItem.Content> </suki:SettingsLayoutItem> </generic:List> </UserControl.Resources> <suki:SukiStackPage Margin="20"> <suki:SukiStackPage.Content> <suki:SettingsLayout Name="Theming" Items="{StaticResource Collection}" /> </suki:SukiStackPage.Content> </suki:SukiStackPage>该页面背后的视图模型 ThemingViewModel.cs 展示了典型的配套写法:IsLightTheme、BackgroundStyle、BackgroundAnimations等可观察属性通过CommunityToolkit.Mvvm的[ObservableProperty]定义,主题切换命令(ChangeBaseTheme、ChangeColorTheme)则直接调用SukiTheme.GetInstance()的实例方法。这一组合就是「SettingsLayout + MVVM 绑定」的完整范例。
四、响应式行为:摘要栏如何随窗口宽度变化
原文档用一句话概括了它的核心能力:"will update with the width of the window"(随窗口宽度更新)。这个「更新」的实质,是左侧摘要栏在超过阈值时展开、低于阈值时收起的双栏/单栏切换。
相关逻辑位于 SettingsLayout.axaml.cs 的DockPanel_SizeChanged:
var desiredSize = e.NewSize.Width > MinWidthWhetherStackSummaryShow ? StackSummaryWidth : 0;即:当SettingsLayout实际宽度大于MinWidthWhetherStackSummaryShow时,摘要栏宽度为目标值StackSummaryWidth;否则宽度为 0(即隐藏摘要栏,内容区占满整行)。宽度切换时控件会调用stack.Animate<double>(WidthProperty, ...)用 800ms 的动画平滑过渡,而不是生硬跳变。
4.1 关键参数:MinWidthWhetherStackSummaryShow
- 默认值 1100(像素):源码中属性注册时指定
1100为默认值。 - 语义:设置页宽度小于该值时,不显示左侧摘要导航,页面退化为单栏堆叠。
- 约束:可配置的最小值为
1,设置时若传入小于 1 的值会被直接忽略(见 SettingsLayout.axaml.cs)。 - 适用场景:如果你的设置项较少、不需要摘要导航,可以把这个阈值调大,让页面在更宽的窗口下也保持单栏;反之,对于宽屏应用可调小阈值,让双栏布局更早出现。
4.2 关键参数:StackSummaryWidth
- 默认值 400(像素)。
- 语义:双栏模式下左侧摘要导航栏的宽度。
- 约束:可配置的最小值为
0,传入负数会被忽略(见 SettingsLayout.axaml.cs)。
这两个属性都是可直接在 XAML 中赋值的公开属性:
<suki:SettingsLayout MinWidthWhetherStackSummaryShow="900" StackSummaryWidth="320"> ... </suki:SettingsLayout>五、源码级机制:分组渲染、摘要导航与自动高亮
UpdateItems()(SettingsLayout.axaml.cs)负责把Items渲染为左右两栏,其内部逻辑能帮助我们理解控件的完整行为:
- 跳过无标题分组:
if (settingsLayoutItem.Header is null) continue;——没有Header的SettingsLayoutItem不会出现在任何一栏中。 - 右侧内容区:每个分组被包装为一个
GroupBox(Header绑定为该项的Header文本,Content放入带Margin = new Thickness(35, 12)的Border内容宿主),GroupBox再放进_stackItems。分组之间以 10×20 的Margin和顶部的 8px 占位Border分隔。 - 左侧摘要区:每个分组的标题同时生成一个
RadioButton(Classes = { "MenuChip" })加入_stackSummary;点击时通过AnimateScroll(x.Value.Y)把右侧ScrollViewer平滑滚动到对应分组的位置,动画时长 800ms、缓动曲线为CubicEaseInOut(见 AnimateScroll)。滚动目标点会额外上移 30px(desiredScroll - 30),避免分组顶部被遮挡。 - 滚动联动高亮:
MyScrollOnScrollChanged在用户滚动右侧内容时,计算每个分组相对_stackItems的 Y 坐标与当前滚动偏移的距离,找出最近的(nearestDistance)分组,并把左侧对应RadioButton的IsChecked置为true(见 SettingsLayout.axaml.cs)。这就是「右侧滚动时左侧摘要自动跟随高亮」的交互来源。 - 生命周期管理:控件挂载到逻辑树(
OnAttachedToLogicalTree)或模板应用(OnApplyTemplate)时会重建内容并订阅集合变化;从逻辑树分离(OnDetachedFromLogicalTree)时会取消进行中的滚动动画、退订事件,避免内存泄漏。
5.1 MenuChip 摘要项的视觉样式
左侧摘要RadioButton的MenuChip样式定义在 SukiUI/Theme/SettingsLayoutStyles.axaml,包含一组状态相关的细节:
- 默认态:透明背景、无边框、左侧带一个
Opacity=0的Ellipse指示点(5×5,颜色取SukiPrimaryColor),并配有 0.4s 的Margin过渡。 :checked选中态:指示点Opacity过渡到 1、文字加粗(DefaultDemiBold)、背景变为SukiPrimaryColor10、边框与前景切换为主题主色SukiPrimaryColor,配合 0.15s~0.3s 的BrushTransition/DoubleTransition动画。:pointerover悬停态:背景变为SukiLightBackground。
这套样式意味着摘要栏的选中/悬停反馈全部由主题资源驱动,在 SukiUI 的亮色与暗色主题下会自动适配。
5.2 移动端 / 触屏适配(Classes="Touch")
SettingsLayout内置了对触屏样式的支持:当在控件上添加Classes="Touch"时,UpdateItems()会同步给每个GroupBox加上Touch样式类(if (Classes.Contains("Touch")) gb.Classes.Add("Touch");),而 SukiUI/Theme/TouchStyles/TouchStyles.axaml 中定义了suki|GroupBox.Touch的专属模板(大圆角、更适合触控的布局),摘要栏MenuChip也配套提供了 SettingsLayoutMenuChipStyles.axaml。Demo 的触屏示例(AllControlsView.axaml)正是这样使用的:
<suki:SettingsLayout Margin="0,25,0,0" Classes="Touch"> <suki:SettingsLayout.Items> <objectModel:ObservableCollection x:TypeArguments="suki:SettingsLayoutItem"> <suki:SettingsLayoutItem Header="Informations"> <!-- 点击编辑、输入框等触控友好的设置项 --> </suki:SettingsLayoutItem> <!-- 更多分组... --> </objectModel:ObservableCollection> </suki:SettingsLayout.Items> </suki:SettingsLayout>六、总结
SettingsLayout把「左侧摘要 + 右侧分组内容」这一设置页范式封装成了声明式控件:
- 快速搭建:在
Items中声明ObservableCollection<SettingsLayoutItem>,为每个分组设置Header与Content即可,内容区支持任意 Avalonia 控件; - 响应式自适应:由
MinWidthWhetherStackSummaryShow(默认 1100)与StackSummaryWidth(默认 400)两个参数控制双栏/单栏切换,宽度变化时以 800ms 动画平滑过渡; - 交互完整:左侧摘要点击可平滑滚动定位、右侧滚动自动联动高亮,
ObservableCollection的运行时增删也会实时反映; - 场景扩展:支持
Classes="Touch"触屏适配,官方 Demo(ThemingView.axaml)提供了与 MVVM 绑定的完整参考实现。
如需深入源码,建议从 SettingsLayout.axaml.cs(响应式与渲染逻辑)、SettingsLayoutItem.cs(分组数据模型)与 SettingsLayoutStyles.axaml(摘要栏样式)三个文件入手。
- UI组件
- 桌面应用
【免费下载链接】SukiUI
UI Theme for AvaloniaUI
相关推荐
10分钟掌握Elementor响应式设计:从零开始构建自适应网站的完整指南
10分钟掌握Elementor响应式设计:从零开始构建自适应网站的完整指南 Elementor是一款功能强大的前端拖放页面构建器,能够帮助用户以最快速度创建高端
CMS前端后端低代码构建响应式布局:gh_mirrors/ui2/ui自适应界面设计
构建响应式布局:gh_mirrors/ui2/ui自适应界面设计 你是否还在为Go语言GUI应用的跨平台界面适配烦恼?本文将带你使用gh_mirrors/ui2
桌面应用UI组件跨平台CUA布局配置:响应式文档站点的页面布局设计
CUA布局配置:响应式文档站点的页面布局设计 引言:为什么响应式布局对技术文档至关重要 在当今多设备访问的时代,技术文档的阅读体验直接影响开发者对项目的理解和采
人工智能AI Agent大模型GUI 自动化MCP 服务模型评测微调强化学习工具调用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考