动态字体与颜色适配
概述
在 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 测试方法
在模拟器中测试:
- 切换深色/浅色模式(⌘+Y)
- 更改文字大小(设置 → 辅助功能 → 显示与文字大小)
- 开启高对比度模式
预览测试:
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")
}
}
}
最佳实践
颜色选择原则:
- 确保在两种模式下都有足够的对比度(至少 4.5:1)
- 避免单纯依赖颜色传递信息(配合形状/纹理)
字体处理建议:
- 测试所有动态字体大小下的布局
- 考虑大字体下的图表压缩策略
性能考虑:
- 对于频繁变化的属性,使用
@Environment而非@State - 复杂颜色计算考虑预生成颜色方案
- 对于频繁变化的属性,使用
设计系统整合:
- 创建统一的主题管理器
- 封装自适应颜色和字体扩展
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))
}
}
通过实现这些技术,您的图表将能够优雅地适应各种用户设备和偏好设置,显著提升应用的可访问性和用户体验。
