12 KiB
12 KiB
Resource Dictionary Architecture / Kiến Trúc Resource Dictionary
Overview / Tổng Quan
Resource Dictionary là nền tảng của Design System trong .NET MAUI. Việc tổ chức đúng cách giúp:
- Re-branding dễ dàng: Chỉ cần thay đổi 1 file
- Maintainability: Code UI sạch, không lặp lại
- Consistency: Đảm bảo UI đồng nhất toàn app
Directory Structure / Cấu Trúc Thư Mục
Resources/
├── Styles/
│ ├── Colors.xaml # Bảng màu chính
│ ├── Typography.xaml # Font families, sizes
│ ├── Spacing.xaml # Margins, paddings
│ └── Theme.xaml # Styles cho controls
├── Fonts/
│ ├── Inter-Regular.ttf
│ └── Inter-Bold.ttf
└── Images/
├── logo.svg
└── icons/
1. Colors.xaml - Bảng Màu
Nguyên tắc đặt tên
- Brand Colors:
Brand*(Primary, Secondary, Accent) - Semantic Colors:
Color*(Success, Warning, Error, Info) - Surface Colors:
Surface*(Background, Card, Overlay) - Text Colors:
Text*(Primary, Secondary, Disabled)
Complete Example
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Resources.Styles.Colors">
<!-- ==================== BRAND COLORS ==================== -->
<!-- Primary brand color - used for main CTAs -->
<Color x:Key="BrandPrimary">#2196F3</Color>
<Color x:Key="BrandPrimaryDark">#1976D2</Color>
<Color x:Key="BrandPrimaryLight">#64B5F6</Color>
<!-- Secondary brand color - used for secondary actions -->
<Color x:Key="BrandSecondary">#FF5722</Color>
<!-- ==================== SEMANTIC COLORS ==================== -->
<Color x:Key="ColorSuccess">#4CAF50</Color>
<Color x:Key="ColorWarning">#FF9800</Color>
<Color x:Key="ColorError">#F44336</Color>
<Color x:Key="ColorInfo">#2196F3</Color>
<!-- ==================== SURFACE COLORS (Theme-aware) ==================== -->
<Color x:Key="SurfaceBackground">
{AppThemeBinding Light=#FAFAFA, Dark=#121212}
</Color>
<Color x:Key="SurfaceCard">
{AppThemeBinding Light=#FFFFFF, Dark=#1E1E1E}
</Color>
<Color x:Key="SurfaceOverlay">
{AppThemeBinding Light=#00000033, Dark=#FFFFFF33}
</Color>
<!-- ==================== TEXT COLORS (Theme-aware) ==================== -->
<Color x:Key="TextPrimary">
{AppThemeBinding Light=#212121, Dark=#FFFFFF}
</Color>
<Color x:Key="TextSecondary">
{AppThemeBinding Light=#757575, Dark=#B0B0B0}
</Color>
<Color x:Key="TextDisabled">
{AppThemeBinding Light=#9E9E9E, Dark=#616161}
</Color>
<Color x:Key="TextOnPrimary">#FFFFFF</Color>
<!-- ==================== BORDER COLORS ==================== -->
<Color x:Key="BorderDefault">
{AppThemeBinding Light=#E0E0E0, Dark=#424242}
</Color>
<Color x:Key="BorderFocused">{StaticResource BrandPrimary}</Color>
</ResourceDictionary>
2. Typography.xaml - Font & Text Styles
Font Registration (MauiProgram.cs)
builder.ConfigureFonts(fonts =>
{
fonts.AddFont("Inter-Regular.ttf", "InterRegular");
fonts.AddFont("Inter-Medium.ttf", "InterMedium");
fonts.AddFont("Inter-Bold.ttf", "InterBold");
fonts.AddFont("Inter-SemiBold.ttf", "InterSemiBold");
});
Typography Scale
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Resources.Styles.Typography">
<!-- ==================== FONT FAMILIES ==================== -->
<OnPlatform x:Key="FontFamilyRegular" x:TypeArguments="x:String">
<On Platform="Android, iOS" Value="InterRegular" />
<On Platform="WinUI" Value="Assets/Fonts/Inter-Regular.ttf#Inter" />
</OnPlatform>
<OnPlatform x:Key="FontFamilyBold" x:TypeArguments="x:String">
<On Platform="Android, iOS" Value="InterBold" />
<On Platform="WinUI" Value="Assets/Fonts/Inter-Bold.ttf#Inter" />
</OnPlatform>
<!-- ==================== FONT SIZES (Scalable) ==================== -->
<!-- Base size: 16 (Body) -->
<x:Double x:Key="FontSizeCaption">12</x:Double>
<x:Double x:Key="FontSizeBody">16</x:Double>
<x:Double x:Key="FontSizeSubtitle">18</x:Double>
<x:Double x:Key="FontSizeTitle">24</x:Double>
<x:Double x:Key="FontSizeHeadline">32</x:Double>
<x:Double x:Key="FontSizeDisplay">48</x:Double>
<!-- ==================== TEXT STYLES ==================== -->
<Style x:Key="TextCaption" TargetType="Label">
<Setter Property="FontFamily" Value="{StaticResource FontFamilyRegular}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeCaption}" />
<Setter Property="TextColor" Value="{StaticResource TextSecondary}" />
</Style>
<Style x:Key="TextBody" TargetType="Label">
<Setter Property="FontFamily" Value="{StaticResource FontFamilyRegular}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeBody}" />
<Setter Property="TextColor" Value="{StaticResource TextPrimary}" />
</Style>
<Style x:Key="TextTitle" TargetType="Label">
<Setter Property="FontFamily" Value="{StaticResource FontFamilyBold}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeTitle}" />
<Setter Property="TextColor" Value="{StaticResource TextPrimary}" />
</Style>
<Style x:Key="TextHeadline" TargetType="Label">
<Setter Property="FontFamily" Value="{StaticResource FontFamilyBold}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeHeadline}" />
<Setter Property="TextColor" Value="{StaticResource TextPrimary}" />
<Setter Property="SemanticProperties.HeadingLevel" Value="Level1" />
</Style>
</ResourceDictionary>
3. Theme.xaml - Control Styles
Implicit vs Explicit Styles
| Type | Syntax | Use Case |
|---|---|---|
| Implicit | <Style TargetType="Button"> |
Default cho tất cả Button |
| Explicit | <Style x:Key="PrimaryButton" TargetType="Button"> |
Áp dụng có chọn lọc |
Complete Example
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Resources.Styles.Theme">
<!-- ==================== BUTTON STYLES ==================== -->
<!-- Primary Button (Filled) -->
<Style x:Key="ButtonPrimary" TargetType="Button">
<Setter Property="BackgroundColor" Value="{StaticResource BrandPrimary}" />
<Setter Property="TextColor" Value="{StaticResource TextOnPrimary}" />
<Setter Property="FontFamily" Value="{StaticResource FontFamilyBold}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeBody}" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Padding" Value="24,12" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="{StaticResource BrandPrimaryDark}" />
<Setter Property="Scale" Value="0.98" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="{StaticResource TextDisabled}" />
<Setter Property="TextColor"
Value="{StaticResource SurfaceCard}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<!-- Secondary Button (Outlined) -->
<Style x:Key="ButtonSecondary" TargetType="Button">
<Setter Property="BackgroundColor" Value="Transparent" />
<Setter Property="TextColor" Value="{StaticResource BrandPrimary}" />
<Setter Property="BorderColor" Value="{StaticResource BrandPrimary}" />
<Setter Property="BorderWidth" Value="2" />
<Setter Property="FontFamily" Value="{StaticResource FontFamilyBold}" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Padding" Value="24,12" />
</Style>
<!-- ==================== ENTRY STYLES ==================== -->
<Style x:Key="EntryDefault" TargetType="Entry">
<Setter Property="BackgroundColor" Value="{StaticResource SurfaceCard}" />
<Setter Property="TextColor" Value="{StaticResource TextPrimary}" />
<Setter Property="PlaceholderColor" Value="{StaticResource TextSecondary}" />
<Setter Property="FontFamily" Value="{StaticResource FontFamilyRegular}" />
<Setter Property="FontSize" Value="{StaticResource FontSizeBody}" />
</Style>
<!-- ==================== FRAME/CARD STYLES ==================== -->
<Style x:Key="CardDefault" TargetType="Frame">
<Setter Property="BackgroundColor" Value="{StaticResource SurfaceCard}" />
<Setter Property="CornerRadius" Value="12" />
<Setter Property="HasShadow" Value="True" />
<Setter Property="Padding" Value="16" />
<Setter Property="BorderColor" Value="Transparent" />
</Style>
</ResourceDictionary>
4. Merged Dictionaries trong App.xaml
Thứ tự quan trọng
<!-- App.xaml -->
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- 1. Colors FIRST (base values) -->
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<!-- 2. Typography (depends on nothing) -->
<ResourceDictionary Source="Resources/Styles/Typography.xaml" />
<!-- 3. Spacing (if any) -->
<ResourceDictionary Source="Resources/Styles/Spacing.xaml" />
<!-- 4. Theme LAST (depends on Colors, Typography) -->
<ResourceDictionary Source="Resources/Styles/Theme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Best Practices / Thực Hành Tốt Nhất
✅ DO
<!-- Dùng StaticResource cho performance -->
<Button BackgroundColor="{StaticResource BrandPrimary}" />
<!-- Dùng AppThemeBinding cho theme-aware colors -->
<Color x:Key="Background">{AppThemeBinding Light=#FFF, Dark=#000}</Color>
<!-- Đặt tên có prefix rõ ràng -->
<Color x:Key="BrandPrimary" />
<Color x:Key="TextPrimary" />
<Style x:Key="ButtonPrimary" />
❌ DON'T
<!-- KHÔNG hard-code màu -->
<Button BackgroundColor="#2196F3" />
<!-- KHÔNG đặt tên mơ hồ -->
<Color x:Key="Blue" />
<Color x:Key="MyColor" />
<!-- KHÔNG gộp tất cả vào App.xaml -->
<Application.Resources>
<Color x:Key="Primary" />
<Color x:Key="Secondary" />
<!-- 500 lines more... -->
</Application.Resources>
Re-branding Workflow
Khi cần thay đổi thương hiệu:
- Chỉ sửa
Colors.xaml- Thay đổi BrandPrimary, BrandSecondary - Cập nhật fonts nếu cần trong
Typography.xaml - Rebuild app - Tất cả UI tự động cập nhật
<!-- Colors.xaml -->
- <Color x:Key="BrandPrimary">#2196F3</Color>
+ <Color x:Key="BrandPrimary">#FF5733</Color>
Related Guidelines
- Typography & Theme - Chi tiết về Font và Dark/Light mode
- Handler Customization - Tùy biến native controls