自定义 Swift Charts 图表外观
了解如何通过使用 chartYAxis、AxisMarks 及其他修饰器,为 Swift Charts 图表添加更多自定义外观和功能。
Swift Charts 是 Apple 在 iOS 16 上推出的一个图表绘制框架,它提供了一套直观且强大的 API,帮助开发者快速构建各种类型的图表。
图表设计规范
有关图表及其坐标轴的设计指南,可参考 Apple 《人机界面指南》中的图表部分:
Swift Charts 基础用法
了解如何为你的应用添加条形图、散点图、折线图等基本的图表,请先阅读我之前的文章:
自定义 Y 坐标轴外观(.chartYAxis)
Chart 提供了 .chartXAxis
和.chartYAxis
修饰器,用于自定义 X 轴和 Y 轴的外观(如刻度、标签、网格线等)。chartYAxis
和 chartXAxis
的功能有很多相似之处,因此这里先通过 .chartYAxis
来演示它们的用法。
.chartXAxis
和.chartYAxis
修饰器均作为用 Chart 组件层,而不是底层的 PointMark 或 LineMark,因此它们适用于所有类型的图表。
可结合 Apple 开发者文档的这篇文章来学习:
主要都是通过 AxisMarks 来实现调整。
使用预设的坐标轴配置(preset)
AxisMarks(preset:) 提供几种预设,简化轴的刻度和标签设置:
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartYAxis {
AxisMarks(preset: .automatic)
}
.frame(height: 300)
.padding()
- .automatic:默认选项,自动调整刻度线和标签,适合大多数场景。
- .aligned:轴上的刻度线和数据点对齐,适合需要数据点精确对齐的情况。
- .extended:显示更多的刻度线和标签,增加轴的信息密度,适合需要详细展示的情况。
调整网格线和标签数(values)
Chart 会根据 Y 轴数值,自动选择默认的网格线和标签数。在下面这个代码中,Chart 默认创建了 4 条网格线:
struct PointMarkChartView: View {
let salesData: [SalesData] = [
SalesData(month: "Jan", sales: 200),
SalesData(month: "Feb", sales: 220),
SalesData(month: "Mar", sales: 190),
SalesData(month: "Apr", sales: 260),
SalesData(month: "May", sales: 280),
SalesData(month: "Jun", sales: 300),
]
var body: some View {
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.frame(height: 300)
.padding()
}
}
通过设置 AxisMarks 的 values 参数,我们可以指定网格线和标签数量:
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartYAxis {
AxisMarks(values: .automatic(desiredCount: 3))
}
.frame(height: 300)
.padding()
.automatic(desiredCount: 3)
指定网格数量为 3,Charts 会指定划分区间:
也可以使用数值数组在坐标轴上标出准确的数值:
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额进行着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartYAxis {
AxisMarks(values: [0, 50, 100, 400])
}
.frame(height: 300)
.padding()
设置标签格式(formate)
format
参数用于指定显示标签的格式化方式。例如,下面这个示例代码为标签添加了百分比符号:
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartYAxis {
AxisMarks(
format: Decimal.FormatStyle.Percent.percent.scale(1),
values: .automatic(desiredCount: 3)
)
}
.frame(height: 300)
.padding()
上面代码中的 Decimal.FormatStyle.Percent.percent.scale(1)
是一种百分比格式化方式,而 format
参数不仅限于百分比,这个参数接受符合 FormatStyle
协议的格式类型,根据数据的类型(如数值、日期等)选择合适的格式。
设置坐标轴方向(position)
将 Y 轴放置在图表的特定位置,例如左侧(leading)或右侧(trailing):
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartYAxis {
AxisMarks(
format: Decimal.FormatStyle.Percent.percent.scale(1),
position: .leading,
values: .automatic(desiredCount: 3)
)
}
.frame(height: 300)
.padding()
调整刻度线粗细、虚实(stroke)
通过 StrokeStyle 来调整轴标记线的粗细,例如下面的例子将标记线的宽度设置为 2。
chartYAxis {
AxisMarks(stroke: StrokeStyle(lineWidth: 2)) // 更粗的标记线
}
还可以自定义线条样式,例如虚线或点线,通过 StrokeStyle 中的 dash 参数可以实现这种效果,还可以结合 lineCap 参数来定义每个点的样式。
完全自定义坐标轴外观(高级)
可以使用以下组件,完全自定义坐标轴线条、标签的样式和颜色。
- AxisGridLine
- AxisTick()
- AxisValueLabel()
一旦采用这种做法,默认样式就会失效。
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartYAxis {
AxisMarks(
values: .automatic(desiredCount: 3)
) { value in
AxisGridLine()
.foregroundStyle(Color.gray.opacity(0.5))
AxisTick()
.foregroundStyle(Color.blue)
AxisValueLabel()
.foregroundStyle(Color.red)
}
}
.frame(height: 300)
.padding()
自定义 X 坐标轴外观(chartXAxis)
AxisMarks
stride
主要用于按一定步长生成坐标轴标记,可以按时间单位(如天、月、年)或数值递增,常见于时间轴或数值轴。
AxisMarks(values: .stride(by: .calendar, count: 3))
在上面的代码中:
by: .calendar
表示你希望按时间单位来生成标记。count: 3
表示每隔 3 个时间单位生成一个标记(例如每 3 天、每 3 个月,取决于时间单位的选择)。
按年递增(每 1 年一个标记):
AxisMarks(values: .stride(by: .year, count: 1))
按月递增(每 3 个月一个标记):
AxisMarks(values: .stride(by: .month, count: 3))
按天递增(每 3 天一个标记):
AxisMarks(values: .stride(by: .day, count: 3))
隐藏 X/Y 坐标轴标签
要隐藏坐标轴标签,只需将 .chartYAxis
设置为空即可:
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartYAxis {
}
.frame(height: 300)
.padding()
自定义 chartForegroundStyleScale
- 待补充
调整图例显示(.chartLegend)
隐藏图例显示
当我们使用.foregroundStyle(by: .value())
为坐标轴设置颜色时,Swift Chart 会自动生成图例:
可以通过设置 .chartLegend(.hidden)
来隐藏图例:
Chart {
ForEach(salesData) { data in
PointMark(
x: .value("Month", data.month),
y: .value("Sales", data.sales)
)
.foregroundStyle(by: .value("Sales", data.sales)) // 按销售额着色
.symbolSize(100) // 自定义数据点大小
}
}
.chartLegend(.hidden)
.frame(height: 300)
.padding()
调整图例位置
.chartLegend
提供了 position
参数,用于设置图例的位置:
.chartLegend(position:.topLeading)
另外,还提供了 spacing
和alignment
参数。