☰
SukiUI SettingsLayout 指南:用响应式设置布局构建自适应的分组设置页面
2026/10/5 2:19:03 网站建设 项目流程
  • UI组件
  • 桌面应用

【免费下载链接】SukiUI

UI Theme for AvaloniaUI

项目地址:https://gitcode.com/gh_mirrors/su/SukiUI
点击查看免费下载

导读

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渲染为左右两栏,其内部逻辑能帮助我们理解控件的完整行为:

  1. 跳过无标题分组:if (settingsLayoutItem.Header is null) continue;——没有Header的SettingsLayoutItem不会出现在任何一栏中。
  2. 右侧内容区:每个分组被包装为一个GroupBox(Header绑定为该项的Header文本,Content放入带Margin = new Thickness(35, 12)的Border内容宿主),GroupBox再放进_stackItems。分组之间以 10×20 的Margin和顶部的 8px 占位Border分隔。
  3. 左侧摘要区:每个分组的标题同时生成一个RadioButton(Classes = { "MenuChip" })加入_stackSummary;点击时通过AnimateScroll(x.Value.Y)把右侧ScrollViewer平滑滚动到对应分组的位置,动画时长 800ms、缓动曲线为CubicEaseInOut(见 AnimateScroll)。滚动目标点会额外上移 30px(desiredScroll - 30),避免分组顶部被遮挡。
  4. 滚动联动高亮:MyScrollOnScrollChanged在用户滚动右侧内容时,计算每个分组相对_stackItems的 Y 坐标与当前滚动偏移的距离,找出最近的(nearestDistance)分组,并把左侧对应RadioButton的IsChecked置为true(见 SettingsLayout.axaml.cs)。这就是「右侧滚动时左侧摘要自动跟随高亮」的交互来源。
  5. 生命周期管理:控件挂载到逻辑树(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

项目地址:https://gitcode.com/gh_mirrors/su/SukiUI
点击查看免费下载

相关推荐

上一篇:BiliDownloader:基于.NET 9的B站视频下载架构设计与实现深度解析
下一篇:Argos Translate:3 条命令搭好离线翻译环境——完整免费指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询