# AtomUI 字体系统 — 使用内置字体包 > 本文档面向 **AtomUI 应用开发者**,介绍如何在应用中启用 AtomUI 内置的 Alibaba Sans 字体包、如何自定义默认字体族,以及字体在主题系统中的消费方式。 --- ## 1. 前置条件 - 项目已引用 `AtomUI.Fonts.AlibabaSans` NuGet 包(或项目引用)。 - 项目已引用 `AtomUI.Desktop.Controls`(或其他 AtomUI 控件包)。 --- ## 2. 在 AtomUI 主题中启用内置字体 ### 2.1 标准用法(推荐) 在 `Application` 类的 `Initialize()` 方法中,通过 `UseAtomUI()` 的 Builder 回调注册字体: ```csharp using AtomUI.Theme; public class App : Application { public override void Initialize() { base.Initialize(); this.UseAtomUI(builder => { builder.UseAlibabaSansFont(); // ← 注册 Alibaba Sans 字体包 builder.UseDesktopControls(); // 注册桌面控件 }); } } ``` 调用 `builder.UseAlibabaSansFont()` 后: 1. `AlibabaSansFontCollection` 被注册到 Avalonia 的 `FontManager`。 2. `fonts:AlibabaSans#Alibaba Sans` URI 变为可用的字体引用。 3. AtomUI 默认的 `DesignToken.FontFamily` Seed Token 已经配置了 `fonts:AlibabaSans#Alibaba Sans` 作为首选字体,因此所有使用 `{atom:SharedTokenResource FontFamily}` 的控件会自动使用 Alibaba Sans。 > **注意:** 如果不调用 `builder.UseAlibabaSansFont()`,`fonts:AlibabaSans#Alibaba Sans` URI 将无法解析,字体会自动 Fallback 到回退链中的下一个可用字体(如 Segoe UI、PingFang SC 等系统字体)。 ### 2.2 完整示例(Gallery 应用) 以下是 AtomUI Gallery 应用的完整配置,作为参考: ```csharp using AtomUI.Desktop.Controls; using AtomUI.Theme; using AtomUI.Theme.Language; public class GalleryApplication : BaseGalleryApplication { public override void Initialize() { base.Initialize(); this.UseAtomUI(builder => { builder.WithDefaultLanguageVariant(LanguageVariant.zh_CN); builder.WithDefaultTheme(IThemeManager.DEFAULT_THEME_ID); builder.UseAlibabaSansFont(); // 启用内置字体 builder.UseDesktopControls(); builder.UseDesktopDataGrid(); builder.UseDesktopColorPicker(); }); } } ``` --- ## 3. 自定义默认字体族 ### 3.1 使用 WithDefaultFontFamily 覆盖 如果你想使用其他字体作为默认字体族(而非 Alibaba Sans),可以通过 `WithDefaultFontFamily()` 方法覆盖: ```csharp this.UseAtomUI(builder => { builder.UseAlibabaSansFont(); // 仍然注册字体包(以防某些控件需要) builder.UseDesktopControls(); // 使用系统字体或其他字体作为默认字体 builder.WithDefaultFontFamily("Segoe UI, PingFang SC, $Default"); }); ``` 或者使用 `FontFamily` 对象: ```csharp using Avalonia.Media; this.UseAtomUI(builder => { builder.UseDesktopControls(); builder.WithDefaultFontFamily(new FontFamily("Inter, Segoe UI, $Default")); }); ``` ### 3.2 工作原理 `WithDefaultFontFamily()` 的工作原理是:在每个主题加载完成后(`ThemeLoaded` 事件),将 `ResourceDictionary` 中的 `SharedTokenKind.FontFamily` 资源值替换为指定的字体族: ```csharp // ApplicationExtensions.cs 内部实现 var defaultFontFamily = themeManagerBuilder.FontFamily; themeManager.ThemeLoaded += (sender, args) => { if (defaultFontFamily != null && args.Theme != null) { var loadedTheme = args.Theme; loadedTheme.ThemeResource[SharedTokenKind.FontFamily] = defaultFontFamily; } }; ``` 这意味着 `WithDefaultFontFamily()` 的优先级**高于** `DesignToken.FontFamily` Seed Token 的默认值,但**不会**影响字号梯度的推导(字号梯度由 `FontSize` Seed Token 推导,与 `FontFamily` 无关)。 --- ## 4. 在 AXAML 中使用字体 Token ### 4.1 全局字体族 在自定义控件或页面中,通过 Token 标记扩展引用字体: ```xml ``` ### 4.2 直接引用嵌入字体 如果你需要在某处使用非默认的嵌入字体(绕过 Token 系统),可以直接使用字体 URI: ```xml ``` 但推荐通过 Token 标记扩展引用,以便主题切换和字体覆盖能自动生效。 ### 4.3 常用字体 Token 速查 | Token 资源键 | 类型 | 默认值 | 说明 | |-------------|------|--------|------| | `FontFamily` | `FontFamily` | Alibaba Sans + Fallback | 全局字体族 | | `FontSize` | `double` | 14 | 基准字号 | | `FontSizeSM` | `double` | 12 | 小号字号 | | `FontSizeLG` | `double` | 16 | 大号字号 | | `FontSizeXL` | `double` | 20 | 超大号字号 | | `FontSizeHeading1` | `double` | 38 | H1 标题字号 | | `FontSizeHeading2` | `double` | 30 | H2 标题字号 | | `FontSizeHeading3` | `double` | 24 | H3 标题字号 | | `FontSizeHeading4` | `double` | 20 | H4 标题字号 | | `FontSizeHeading5` | `double` | 16 | H5 标题字号 | | `FontSizeIcon` | `double` | 12 | 图标字号 | | `FontWeightStrong` | `FontWeight` | SemiBold | 加粗字重 | | `RelativeLineHeight` | `double` | ≈1.571 | 基准行高 | | `FontHeight` | `double` | 22 | 文字高度 (px) | --- ## 5. 字体继承机制 AtomUI 的字体设置利用了 Avalonia 的 **属性继承(Property Inheritance)** 机制: 1. **Window** / **PopupRoot** / **OverlayPopupHost** 控件主题设置 `FontFamily` 和 `FontSize`。 2. 所有子控件自动继承父控件的 `FontFamily` 和 `FontSize` 值。 3. 个别控件可以在自己的主题中覆盖这些值(如标题控件使用 `FontSizeHeading*`)。 ``` Window FontFamily = {atom:SharedTokenResource FontFamily} ← 根级设置 FontSize = {atom:SharedTokenResource FontSize} │ ├── StackPanel (继承 FontFamily, FontSize) │ ├── TextBlock (继承) → 14px Alibaba Sans │ └── Button (继承) → 14px Alibaba Sans │ └── Typography.Title (覆盖 FontSize) └── TextBlock FontSize = FontSizeHeading1 → 38px Alibaba Sans ``` --- ## 6. 在纯 Avalonia 应用中使用(不使用 AtomUI 主题) 如果你的应用不使用 AtomUI 主题系统,但仍想使用 Alibaba Sans 字体,可以通过 `AppBuilder` 扩展方法注册: ```csharp class Program { [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .WithAlibabaSansFont() // ← 纯 Avalonia 方式注册字体 .LogToTrace(); } ``` 然后在 XAML 中直接引用: ```xml ``` 或者设置为全局默认字体: ```xml title="App.axaml" fonts:AlibabaSans#Alibaba Sans ``` --- ## 7. 排障指南 ### 7.1 字体显示为系统默认字体(不是 Alibaba Sans) **可能原因:** 1. 忘记调用 `builder.UseAlibabaSansFont()` — 字体包未注册。 2. `fonts:AlibabaSans#Alibaba Sans` 中的字体族名称拼写错误。 3. 字体文件未正确嵌入 — 检查 `.csproj` 中是否有 ``。 **诊断方法:** 检查应用启动日志,Avalonia 在找不到字体时通常会有警告日志。 ### 7.2 中文字符显示为方块(□) **可能原因:** 使用的字体不包含中文字符。Alibaba Sans 包含中文字符集,但如果通过 `WithDefaultFontFamily()` 替换为不支持中文的西文字体(如 Inter),中文字符将无法显示。 **解决方案:** 在字体族回退链中包含支持中文的字体: ```csharp builder.WithDefaultFontFamily("Inter, PingFang SC, Microsoft YaHei, $Default"); ``` ### 7.3 字号梯度不符合预期 `FontSize` Seed Token 的默认值为 14。如果需要修改基准字号,需要在主题 XML 配置文件中覆盖 `FontSize` Seed Token,所有派生的字号梯度会自动重新计算。