Swift组合图表层级顺序问题:Area Mark始终置顶
解决SwiftUI Chart中Mark层级覆盖问题
问题原因
SwiftUI Chart的Mark渲染层级是按类型优先级固定的:AreaMark > LineMark > PointMark,所以无论你在代码中调整Mark的顺序,AreaMark都会默认显示在最上层。而同类型Mark的层级则由它们在Chart中的生成顺序决定,后生成的会覆盖先生成的。
解决方案
通过ZStack叠加多个Chart来手动控制层级:
- 底层Chart仅渲染
AreaMark - 上层Chart渲染所有
LineMark和PointMark,并调整同类型Mark的生成顺序来控制它们的层级
修改后的代码示例
var body: some View { ScrollView(.horizontal, showsIndicators: false) { ZStack { // 底层:仅渲染AreaMark Chart(data.filter { $0.owner == .global }) { mark in AreaMark( x: .value("day", mark.day), y: .value("score", mark.score) ) .foregroundStyle(.indigo) .opacity(1) .interpolationMethod(.catmullRom) } .chartXScale(domain: dates) .chartYScale(domain: getYAxis()) // 上层:渲染Line和Point Mark,控制顺序调整层级 Chart(data) { mark in // Friends line - 先渲染,会被后面的Player Line覆盖 if mark.owner == .friends { LineMark( x: .value("day", mark.day), y: .value(mark.type == .score ? "score" : "seconds", mark.score), series: .value("Friends Score", "friends") ) .interpolationMethod(.catmullRom) .foregroundStyle(.yellow) .lineStyle(StrokeStyle(lineWidth: 3, dash: [5, 10])) } // Player line - 后渲染,显示在Friends Line上方 if mark.owner == .player { LineMark( x: .value("day", mark.day), y: .value("score", mark.score), series: .value("Player Score", "player") ) .interpolationMethod(.catmullRom) } // Friends annotation if mark.owner == .friends { PointMark( x: .value("day", mark.day), y: .value("score", mark.score) ) .interpolationMethod(.catmullRom) .symbol() { Circle() .strokeBorder(.black) .background(Circle().fill(.orange)) .frame(width: 10) } .annotation() { Text("\(mark.score)") } } // Player annotation - 后渲染,显示在Friends标注上方 if mark.owner == .player { PointMark( x: .value("day", mark.day), y: .value(dataPoint == .score ? "score" : "seconds", mark.score) ) .symbol() { Circle() .strokeBorder(.black) .background(Circle().fill(.blue)) .frame(width: 10) } .annotation() { Text("\(mark.score)") } .interpolationMethod(.catmullRom) } } .chartXScale(domain: dates) .chartYScale(domain: getYAxis()) } .frame(minWidth: screen.size.height*3, maxHeight: screen.size.height/3) } }
说明
- 用ZStack将两个Chart叠加,确保上层的Line/Point完全显示在Area之上
- 在同一个上层Chart中,将需要显示在上方的Mark(比如Player Line和标注)放在后面生成,覆盖先渲染的Friends相关Mark
- 两个Chart都设置相同的X/Y轴范围,保证对齐一致
内容的提问来源于stack exchange,提问作者Fiona Kate
相关产品推荐
相关产品推荐

