我正在尝试使用新的 SectorMark 创建一个半圆环图,如图像所示:
到目前为止,我刚刚使用示例数据创建了一个普通的甜甜圈来填充它:
struct Score: Identifiable {
let id = UUID()
let type: String
let value: Int
}
@State private var scores: [Score] = [
.init(type: "Hits", value: 1),
.init(type: "Misses", value: 9)
]
Chart(scores) { score in
SectorMark(
angle: .value("Values", score.value),
innerRadius: .ratio(0.9),
outerRadius: .ratio(0.7)
)
.foregroundStyle(
by: .value("Type", score.type)
)
}
在我试图创建的图表中,我仅使用部分来显示一个人的分数(他/她回答正确和错误的答案数量)。
使用 SectorMark 是否有可能实现这一目标?我从这个苹果视频中发现了这个新功能:https://developer.apple.com/videos/play/wwdc2023/10037/
所以我决定使用@Sweeper建议的方法,它对我有用。由于我的图表仅使用两个值,因此我使用了带有两个圆形形状的 ZStack,如下所示:
ZStack {
Circle()
.trim(from: 0.0, to: 0.7)
.stroke(Color.defaultBlue, style: StrokeStyle(lineWidth: 8, lineCap: .round))
.frame(width: screenSize.width * 0.4, height: screenSize.height * 0.2)
.rotationEffect(.degrees(-215))
Circle()
.trim(from: 0.0, to: CGFloat(-- here you can use a percentage of your choice --) / (100 / 0.7))
.stroke(Color.blue, style: StrokeStyle(lineWidth: 8, lineCap: .round))
.frame(width: screenSize.width * 0.4, height: screenSize.height * 0.2)
.rotationEffect(.degrees(-215))
}
这就是我的结果,正是我想要的:
(我从代码中删除了文本视图)
但是,如果您想知道是否有一种使用 SectorMark 的方法(这是本文最初的问题),是的,有,但不太优雅。
想象一下,如果您有像我这样的样本,即为图表使用两个值,您需要:
这是代码:
struct Score: Identifiable {
let id = UUID()
let type: String
let value: Int
let color: Color
}
struct ContentView: View {
@State private var scores: [Score] = [
.init(type: "Hits", value: 1, color: .blue),
.init(type: "Misses", value: 9, color: .green),
.init(type: "", value: 10, color: .white)
]
var body: some View {
Chart(scores) { score in
SectorMark(
angle: .value("Values", score.value),
innerRadius: .ratio(0.9),
outerRadius: .ratio(0.7)
)
.foregroundStyle(score.color)
.foregroundStyle(
by: .value("Type", score.type)
)
}
.rotationEffect(.degrees(-90))
}
}
这就是结果:
您可能需要使用文本视图通过 VStack 添加图例。感谢 @Claude31 在 Apple 论坛上为我提供了帮助 (https://developer.apple.com/forums/thread/748142)
SectorMark 有很大的潜力,也许苹果可以在下次更新中实施半甜甜圈方法。
圆形仪表是另一个可能满足您需求的 SwiftUI 选项。仪表只需要当前、最小值和最大值。
struct GaugeView: View {
@State private var current = 3.0
let min = 0.0
let max = 10.0
let gradient = Gradient(colors: [.blue, .black])
var body: some View {
Gauge(value: current, in: min...max) {
} currentValueLabel: {
Text("\(Int(current))")
.foregroundColor(.blue)
} minimumValueLabel: {
Text("\(Int(min))")
} maximumValueLabel: {
Text("\(Int(max))")
}
.gaugeStyle(.accessoryCircular)
.tint(gradient)
}
}
看起来像这样: