Swift Chart:拖动时更新chartOverlay指示器为对应线条颜色
解决SwiftUI Chart中追踪指示器匹配渐变线条颜色的问题
问题核心:foregroundstyle(for:)方法无法获取线条渐变颜色,是因为该方法需要对应具体的Mark实例,而通过proxy.value(at:)拿到的是数据值,并非Mark引用,因此返回nil。
解决方案:基于Y轴位置计算渐变颜色
由于你的渐变是沿Y轴从底部(绿色)到顶部(红色)的线性渐变,我们可以通过指示器在绘图区域的Y坐标比例,直接计算对应位置的颜色,无需依赖foregroundstyle(for:)。
修改后的完整代码:
struct ContentView: View { @State private var numbers = (0...10).map { _ in Int.random(in: 0...10) } @State private var indicatorLocation = CGPoint.zero @State private var indicatorColor: Color = .white var body: some View { Chart { ForEach(Array(zip(numbers, numbers.indices)), id: \.1) { number, index in LineMark( x: .value("Index", index), y: .value("Value", number) ) .foregroundStyle( .linearGradient( colors: [.green, .red], startPoint: .bottom, endPoint: .top ) ) } } .chartOverlay { proxy in GeometryReader { geometry in let plotFrame = geometry[proxy.plotAreaFrame] Circle() .fill(indicatorColor) .frame(width: 30, height: 30) .offset(x: -15, y: -15) .position(indicatorLocation) Rectangle().fill(.clear).contentShape(Rectangle()) .gesture( DragGesture() .onChanged { value in // 转换到绘图区域内的坐标 let plotLocation = CGPoint( x: value.location.x - plotFrame.origin.x, y: value.location.y - plotFrame.origin.y ) // 获取对应的数据点 guard let (index, number) = proxy.value(at: plotLocation, as: (Int, Double).self) else { return } // 计算指示器在Y轴的位置(转换到绘图区域内的Y坐标) if let yPosition = proxy.position(forY: .value("Value", number)) { let adjustedY = plotFrame.origin.y + yPosition indicatorLocation = CGPoint(x: value.location.x, y: adjustedY) // 计算Y轴方向的比例,获取渐变颜色 let yRatio = (adjustedY - plotFrame.minY) / plotFrame.height // 因为渐变是bottom(绿)到top(红),所以比例从0到1对应绿到红 indicatorColor = Color( uiColor: UIColor( red: yRatio, green: 1 - yRatio, blue: 0, alpha: 1 ) ) } } ) } } } }
关键说明:
- 坐标转换:先将手势位置转换为绘图区域内的坐标,确保后续计算的准确性。
- 颜色计算逻辑:计算指示器Y坐标在绘图区域内的比例(
yRatio),范围从0(底部,绿色)到1(顶部,红色),通过RGB值直接匹配原渐变的颜色过渡。 - 修正ForEach的id:原代码用
\.0(number)作为id,当出现重复数值时会导致视图更新异常,改为用\.1(index)更可靠。
内容的提问来源于stack exchange,提问作者peter flanagan
相关产品推荐
相关产品推荐

