You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取经scaleEffect变换的Swift Chart中正确的点击像素?

问题:Swift Chart 翻转后点击坐标匹配异常

为了让Swift Chart在ScrollView初始显示时滚动到右侧,我给图表添加了scaleEffect(x: -1)进行水平翻转,再给外层ScrollView添加同样的翻转来还原视觉效果。但这样做后,chartOverlay中的onTapGesture无法获取用户实际点击的逻辑像素,导致打印的日期不正确。

我有一个临时解决方案,但它无法处理两种场景:

  • 图表尺寸小于屏幕时自动扩展的情况
  • 图表左右两侧存在不可预测间距的情况

另外我尝试过用onAppear调用scrollTo直接滚动到右侧作为替代方案,但这个方案存在bug,在iOS16上表现尤为明显。

示例代码

import SwiftUI
import Charts

struct ContentView: View {
    var dates = (0..<100).map { Calendar.current.date(byAdding: .day, value: $0, to: Date())! }

    var body: some View {
        GeometryReader { geo in
            ScrollViewReader { proxy in
                ScrollView(.horizontal) {
                    HStack(spacing:0) {
                        Chart {
                            ForEach(dates, id:\.self) { date in
                                LineMark(x: .value("day", date),
                                         y: .value("value", 1))
                            }
                        }
                        .chartXAxis {
                            AxisMarks(preset: .extended,
                                      position: .bottom,
                                      values: .stride (by: .day)) { value in
                                let label = value.as(Date.self)!.formatted(.dateTime.day()) + "\n" +
                                    value.as(Date.self)!.formatted(.dateTime.month())
                                AxisValueLabel(collisionResolution: .greedy) {
                                    Text(label)
                                }
                            }
                        }
                        .frame(minWidth: 40.0*CGFloat(dates.count)+10.0, maxWidth:.infinity, minHeight: geo.size.height, maxHeight:.infinity, alignment: .center)
                        .scaleEffect(x: -1, y: 1)
                    }
                    .frame(minWidth: geo.size.width, maxWidth:.infinity, maxHeight:.infinity, alignment:.center)
                    .chartOverlay { proxy in
                        GeometryReader { geometry in
                            Rectangle().fill(.clear).contentShape(Rectangle())
                                .onTapGesture { location in onTap(at: location, geometry: geometry, proxy: proxy) }
                        }
                    }
                }
                .frame(maxWidth:.infinity, maxHeight:.infinity, alignment:.center)
                .scaleEffect(x: -1, y: 1)
            }
        }
    }
    
    func onTap(at: CGPoint, geometry: GeometryProxy, proxy: ChartProxy) {
        let origin = geometry[proxy.plotAreaFrame].origin
        let selectedDate = proxy.value(atX: at.x - origin.x, as: Date.self)
        if selectedDate != nil {
            print("1 tapped on date \(selectedDate)") // 无翻转时正常工作
        }

        let selectedDate2 = proxy.value(atX: (40.0*CGFloat(dates.count)+10.0 - at.x) - origin.x, as: Date.self)
        if selectedDate2 != nil {
            print("2 tapped on date \(selectedDate2)") // 翻转后无法正常工作
        }
    }
}

内容的提问来源于stack exchange,提问作者John Cashew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:43:34