# 04-外观与主题系统 阑山桌面支持暗色/浅色主题切换,插件需要适配宿主的视觉风格,保持界面一致性。 --- ## 🎨 主题系统概述 阑山桌面使用 Avalonia UI 的主题系统,支持: - **浅色主题** - 明亮背景,深色文字 - **深色主题** - 深色背景,浅色文字 - **跟随系统** - 自动匹配 Windows/macOS 主题 --- ## 🌗 检测当前主题 ### 在组件中检测 ```csharp using Avalonia; using Avalonia.Styling; public class MyWidget : Border { public MyWidget(PluginDesktopComponentContext context) { // 检测当前主题 var isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark; // 根据主题设置颜色 UpdateTheme(isDark); // 监听主题变化 if (Application.Current != null) { Application.Current.ActualThemeVariantChanged += (_, _) => { var newIsDark = Application.Current.ActualThemeVariant == ThemeVariant.Dark; UpdateTheme(newIsDark); }; } } private void UpdateTheme(bool isDark) { Background = new SolidColorBrush( isDark ? Color.Parse("#FF1E1E1E") : Color.Parse("#FFFFFFFF")); Foreground = new SolidColorBrush( isDark ? Colors.White : Colors.Black); } } ``` --- ## 📐 圆角系统 插件必须使用宿主提供的圆角系统,确保与内置组件视觉一致。 ### 为什么插件不能使用 XAML 资源 插件运行在独立的 `AssemblyLoadContext` 中,无法直接访问宿主的资源字典。因此 `{DynamicResource DesignCornerRadiusComponent}` 在插件 XAML 中无效。 ### 使用代码设置圆角 ```csharp public class MyWidget : Border { public MyWidget(PluginDesktopComponentContext context) { // 方法 1:使用预设(推荐) CornerRadius = context.Appearance.ResolveCornerRadius( PluginCornerRadiusPreset.Component); // 方法 2:带最小/最大值限制 CornerRadius = context.Appearance.ResolveCornerRadius( PluginCornerRadiusPreset.Component, minimum: new CornerRadius(8), maximum: new CornerRadius(24)); // 方法 3:自定义基础值,应用全局缩放 CornerRadius = context.Appearance.ResolveScaledCornerRadius( baseRadius: 16, minimum: 8, maximum: 32); } } ``` ### 圆角预设 | 预设 | 默认值 | 用途 | |-----|-------|------| | `Micro` | 6px | 微小元素 | | `Xs` | 12px | 小元素、图标容器 | | `Sm` | 14px | 小卡片 | | `Md` | 20px | 普通按钮/卡片 | | `Lg` | 28px | 大面板 | | `Xl` | 32px | 强调容器 | | `Island` | 36px | 大型容器 | | `Component` | 18px | **桌面组件标准** | | `Default` | 自适应 | 根据尺寸自动计算 | ### 内部元素圆角 组件内部的卡片、按钮应使用更小的圆角: ```csharp // 组件根容器 - 使用 Component 预设 CornerRadius = context.ResolveCornerRadius(PluginCornerRadiusPreset.Component); // 内部卡片 - 使用 Md 预设 var innerCard = new Border { CornerRadius = context.ResolveCornerRadius(PluginCornerRadiusPreset.Md), Background = new SolidColorBrush(Colors.LightGray) }; // 按钮 - 使用 Sm 预设 var button = new Button { CornerRadius = context.ResolveCornerRadius(PluginCornerRadiusPreset.Sm) }; ``` --- ## 🎨 颜色系统 ### 推荐的颜色策略 ```csharp // 透明背景(推荐)- 让宿主壁纸透出 Background = new SolidColorBrush(Colors.Transparent); // 毛玻璃效果 Background = new SolidColorBrush(Color.Parse(isDark ? "#40FFFFFF" : "#40000000")); // 卡片背景 Background = new SolidColorBrush(Color.Parse(isDark ? "#FF2D2D2D" : "#FFFFFFFF")); // 强调色(使用系统强调色) var accentColor = Color.Parse("#FF0078D4"); // 阑山桌面主色调 ``` ### 文字颜色 ```csharp // 主要文字 Foreground = new SolidColorBrush(isDark ? Colors.White : Colors.Black); // 次要文字 Foreground = new SolidColorBrush(isDark ? Color.Parse("#FFCCCCCC") : Color.Parse("#FF666666")); // 禁用文字 Foreground = new SolidColorBrush(isDark ? Color.Parse("#FF666666") : Color.Parse("#FF999999")); ``` --- ## 🔄 响应外观变化 ### 订阅外观变化事件 ```csharp public class MyWidget : Border { public MyWidget(PluginDesktopComponentContext context) { // 订阅外观变化 context.Appearance.AppearanceChanged += (_, _) => { UpdateAppearance(); }; // 初始化 UpdateAppearance(); } private void UpdateAppearance() { // 重新应用圆角(用户可能调整了全局圆角设置) var context = ...; // 获取 context CornerRadius = context.Appearance.ResolveCornerRadius( PluginCornerRadiusPreset.Component); // 更新主题颜色 var isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark; UpdateThemeColors(isDark); } } ``` --- ## 🧩 使用 FluentAvalonia 控件 推荐使用 FluentAvalonia 控件库,它们自动适配主题: ```xml ``` ### 常用 FluentAvalonia 控件 | 控件 | 用途 | |-----|------| | `SettingsExpander` | 设置项展开器 | | `SettingsCard` | 设置卡片 | | `ColorPicker` | 颜色选择器 | | `NumberBox` | 数字输入框 | | `ToggleSwitch` | 开关 | --- ## 💡 最佳实践 ### 1. 始终使用透明背景 ```csharp // ✅ 好的做法 Background = new SolidColorBrush(Colors.Transparent); // ❌ 避免硬编码背景色 Background = new SolidColorBrush(Colors.White); ``` ### 2. 组件根容器必须使用 Component 圆角 ```csharp // ✅ 正确 CornerRadius = context.ResolveCornerRadius(PluginCornerRadiusPreset.Component); // ❌ 错误 - 硬编码 CornerRadius = new CornerRadius(18); ``` ### 3. 响应主题变化 ```csharp // ✅ 订阅变化事件 Application.Current.ActualThemeVariantChanged += OnThemeChanged; // ❌ 只在构造函数中设置一次 ``` ### 4. 使用语义化颜色 ```csharp // ✅ 根据用途选择颜色 var primaryText = isDark ? Colors.White : Colors.Black; var secondaryText = isDark ? Color.Parse("#FFCCCCCC") : Color.Parse("#FF666666"); // ❌ 避免随意使用颜色 var textColor = Color.Parse("#FF123456"); ``` --- ## 🐛 常见问题 ### 问题 1:圆角不生效 **原因:** 在 XAML 中使用 `{DynamicResource}` **解决:** 在代码中设置圆角(见上文) ### 问题 2:主题切换后颜色不对 **原因:** 没有订阅主题变化事件 **解决:** 添加 `ActualThemeVariantChanged` 事件处理 ### 问题 3:组件与内置组件风格不一致 **排查:** 1. 检查圆角是否使用 `PluginCornerRadiusPreset.Component` 2. 检查背景是否透明 3. 检查是否使用了 FluentAvalonia 控件 --- ## 📚 参考资源 - [CORNER_RADIUS_SPEC.md](../../docs/CORNER_RADIUS_SPEC.md) - [VISUAL_SPEC.md](../../docs/VISUAL_SPEC.md) - [FluentAvalonia 文档](https://github.com/amwx/FluentAvalonia) --- ## 🎯 下一步 学习插件间通信: 👉 **[05-插件间通信](05-插件间通信.md)** - 与其他插件协作 --- *最后更新:2026年4月*