我有一个简单的 Swift Chart,我试图将 RuleMark 放在 BarMark 后面。
当 RuleMark 位于 BarMark 之前时,条形会出现问题,并会随着选定内容的移动而移动。以下是可重现的示例。
import SwiftUI
import Charts
struct datStruct: Identifiable {
let id = UUID()
let label: String
let value: Int
}
struct ContentView: View {
let dat = [
datStruct(label: "A", value: 1),
datStruct(label: "B", value: 2),
datStruct(label: "C", value: 3)
]
@State var rawSelection: String?
var selection: datStruct? {
guard let rawSelection else {return nil}
return dat.first(where: { $0.label == rawSelection })
}
var body: some View {
Chart(){
if let selection {
RuleMark(x: .value("label", selection.label))
.foregroundStyle(.red)
}
ForEach(dat) {dat in
BarMark(x: .value("label", dat.label), y: .value("count", dat.value))
}
}
.chartXSelection(value: $rawSelection)
}
}
#Preview {
ContentView()
}
当 RuleMark 移动到 BarMark 之后,并应用负的 ZIndex 时,规则会按预期显示在栏的后面。但是,当我为选定内容添加动画时,规则会短暂地显示在栏的上方,然后动画移动到栏的后面。
如何才能始终显示 BarMark 后面的 RuleMark 并应用动画?
import SwiftUI
import Charts
struct datStruct: Identifiable {
let id = UUID()
let label: String
let value: Int
}
struct ContentView: View {
let dat = [
datStruct(label: "A", value: 1),
datStruct(label: "B", value: 2),
datStruct(label: "C", value: 3)
]
@State var rawSelection: String?
var selection: datStruct? {
guard let rawSelection else {return nil}
return dat.first(where: { $0.label == rawSelection })
}
var body: some View {
Chart(){
ForEach(dat) {dat in
BarMark(x: .value("label", dat.label), y: .value("count", dat.value))
}
if let selection {
RuleMark(x: .value("label", selection.label))
.foregroundStyle(.red)
.zIndex(-1)
}
}
.chartXSelection(value: $rawSelection.animation())
}
}
#Preview {
ContentView()
}
条形图“随所选内容移动”与图表自动排列 X 轴离散值的方式有关。默认行为是“按出现顺序排列”。
假设您选择“A”,图表中出现的第一个 X 值是“A”,因此 X 轴依次排列为“A”、“B”、“C”。然后,当您将手指移到“B”时,X 轴的 X
RuleMark
值现在位于“B”。这会将 X 值的顺序更改为“B”、“A”、“C”。这会导致条形移动到新的位置。因此,您的手指现在又位于“A”,因此条形再次重新排列为“A”、“B”、“C”,如此循环往复。您可以向添加
chartXScale
修饰符Chart
,以指定 x 值的精确排序方式,以阻止它们自动排序。例如,这里我按照它们在 中出现的顺序对它们进行了排序
dat
。或者使用 a
chartOverlay
代替RuleMark
。在覆盖层中,放置Rectangle
宽度为 1 的 a 。