Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 动态字体与颜色适配

动态字体与颜色适配

概述

在 SwiftUI 图表开发中,动态字体和颜色适配是确保应用可访问性和多主题支持的关键技术。本章将介绍如何实现以下功能:

  • 响应系统字体大小变化
  • 适配深色/浅色模式
  • 创建自适应颜色方案
  • 处理高对比度模式

1. 响应动态字体

1.1 使用 .font() 修饰符

Text("数据标签")
    .font(.system(.body, design: .rounded)) // 使用系统动态字体
    .fontWeight(.medium)

1.2 图表中的字体适配

Chart {
    ForEach(data) { item in
        BarMark(
            x: .value("Category", item.category),
            y: .value("Value", item.value)
        )
        .annotation {
            Text("\(item.value)")
                .font(.caption2) // 使用动态字体尺寸
        }
    }
}

1.3 检测字体大小变化

@Environment(\.sizeCategory) var sizeCategory

var body: some View {
    if sizeCategory >= .accessibilityLarge {
        // 调整大字体下的布局
    }
}

2. 颜色适配方案

2.1 基础颜色适配

// 定义自适应颜色
let chartColor = Color("ChartPrimary") // 在 Asset Catalog 中设置深色/浅色变体

// 使用方式
BarMark()
    .foregroundStyle(chartColor)

2.2 响应颜色模式变化

@Environment(\.colorScheme) var colorScheme

var body: some View {
    let gradient = colorScheme == .dark ? 
        Gradient(colors: [.blue, .purple]) : 
        Gradient(colors: [.green, .yellow])
    
    LineMark()
        .foregroundStyle(LinearGradient(gradient: gradient))
}

2.3 高对比度模式支持

@Environment(\.accessibilityContrast) var contrast

var body: some View {
    let barColor = contrast == .increased ? 
        Color.red : 
        Color(red: 0.8, green: 0.2, blue: 0.2)
    
    BarMark()
        .foregroundStyle(barColor)
}

3. 完整实现案例

3.1 自适应柱状图组件

struct AdaptiveBarChart: View {
    @Environment(\.colorScheme) var colorScheme
    @Environment(\.sizeCategory) var sizeCategory
    
    let data: [DataPoint]
    
    private var barWidth: CGFloat {
        sizeCategory.isAccessibilityCategory ? 20 : 10
    }
    
    private var labelFont: Font {
        sizeCategory >= .large ? .subheadline : .caption
    }
    
    var body: some View {
        Chart(data) { item in
            BarMark(
                x: .value("Day", item.day),
                y: .value("Sales", item.sales)
            )
            .foregroundStyle(
                colorScheme == .dark ? 
                Color.blue.gradient : 
                Color.cyan.gradient
            )
            .annotation {
                Text("\(item.sales)")
                    .font(labelFont)
            }
        }
        .chartXAxis {
            AxisMarks(values: .automatic) { _ in
                AxisValueLabel()
                    .font(.system(size: 12))
            }
        }
        .frame(height: sizeCategory.isAccessibilityCategory ? 400 : 300)
    }
}

3.2 测试方法

  1. 在模拟器中测试:

    • 切换深色/浅色模式(⌘+Y)
    • 更改文字大小(设置 → 辅助功能 → 显示与文字大小)
    • 开启高对比度模式
  2. 预览测试:

struct AdaptiveBarChart_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            AdaptiveBarChart(data: sampleData)
                .previewDisplayName("Light Mode")
            
            AdaptiveBarChart(data: sampleData)
                .preferredColorScheme(.dark)
                .previewDisplayName("Dark Mode")
            
            AdaptiveBarChart(data: sampleData)
                .environment(\.sizeCategory, .accessibilityExtraLarge)
                .previewDisplayName("Large Text")
        }
    }
}

最佳实践

  1. 颜色选择原则:

    • 确保在两种模式下都有足够的对比度(至少 4.5:1)
    • 避免单纯依赖颜色传递信息(配合形状/纹理)
  2. 字体处理建议:

    • 测试所有动态字体大小下的布局
    • 考虑大字体下的图表压缩策略
  3. 性能考虑:

    • 对于频繁变化的属性,使用 @Environment 而非 @State
    • 复杂颜色计算考虑预生成颜色方案
  4. 设计系统整合:

    • 创建统一的主题管理器
    • 封装自适应颜色和字体扩展
extension Color {
    static let adaptiveBlue = Self {
        $0 == .dark ? Color.blue : Color.cyan
    }
}

extension View {
    func adaptiveFont(_ style: Font.TextStyle) -> some View {
        self.modifier(AdaptiveFont(style: style))
    }
}

通过实现这些技术,您的图表将能够优雅地适应各种用户设备和偏好设置,显著提升应用的可访问性和用户体验。

Last Updated:: 5/18/25, 10:44 AM