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

SwiftUI中点击正方形图片获取相对坐标异常问题求助

SwiftUI图片点击坐标异常与拖拽越界问题修复

问题根源

  1. X坐标计算错误:你用了外层GeometryReader的size.width作为分母,但这个GeometryReader的宽度是父容器的宽度(远大于图片实际显示宽度),导致计算出的相对X值偏小。
  2. 拖拽触发区域外事件:DragGesture(minimumDistance: 0)会识别整个拖拽路径,当拖拽到图片外时,value.location会指向图片外的坐标,从而触发异常事件。

修复方案

1. 正确获取图片实际显示尺寸计算相对坐标

将GeometryReader嵌套在Image的背景中,直接获取图片自身的显示frame,而非外层容器的尺寸。这样计算出的相对坐标才是基于图片实际大小的。

2. 替换为TapGesture(更适合点击场景)

如果你的需求只是点击获取坐标,TapGesture比DragGesture更合适,它只会响应图片范围内的点击事件,不会触发拖拽越界的问题。如果需要支持拖拽标记位置,可以保留DragGesture但添加坐标校验逻辑。

修复后的完整代码

import SwiftUI

struct PositionsDetailsView: View {
    let match: Match
    @Binding var selectedPosition: (x: CGFloat, y: CGFloat)?
    var player: Player

    @Environment(\.presentationMode) var presentationMode
    @State private var tappedPosition: CGPoint? = nil
    @State private var imageSize: CGSize = .zero

    var body: some View {
        VStack {
            Text("Tik op de afbeelding om coördinaten te krijgen")
                .padding()

            GeometryReader { outerGeo in
                Image("half_korfbal_veld")
                    .resizable()
                    .scaledToFit()
                    .overlay(
                        tappedPosition.map { position in
                            Circle()
                                .fill(Color.red)
                                .frame(width: 10, height: 10)
                                .position(position)
                        }
                    )
                    .background(
                        GeometryReader { imageGeo in
                            Color.clear
                                .onAppear {
                                    // 获取图片实际显示的尺寸
                                    imageSize = imageGeo.size
                                }
                        }
                    )
                    .gesture(
                        TapGesture()
                            .onEnded { location in
                                // 基于图片实际尺寸计算相对坐标
                                let relativeX = location.x / imageSize.width
                                let relativeY = location.y / imageSize.height
                                
                                tappedPosition = location
                                selectedPosition = (x: relativeX, y: relativeY)
                                print("图片实际宽高: \(imageSize.width) x \(imageSize.height)")
                                print("相对坐标: (\(relativeX), \(relativeY))")
                            }
                    )
            }
            .frame(height: 300)

            Button("Sluiten") {
                presentationMode.wrappedValue.dismiss()
            }
            .padding()
        }
        .padding()
    }
}

额外优化说明

  • 如果需要支持拖拽标记位置,保留DragGesture但添加坐标校验:
    DragGesture(minimumDistance: 0)
        .onEnded { value in
            // 校验坐标是否在图片范围内
            guard value.location.x >= 0, 
                  value.location.x <= imageSize.width,
                  value.location.y >= 0,
                  value.location.y <= imageSize.height else {
                return // 忽略图片外的拖拽事件
            }
            let relativeX = value.location.x / imageSize.width
            let relativeY = value.location.y / imageSize.height
            
            tappedPosition = value.location
            selectedPosition = (x: relativeX, y: relativeY)
        }
    
  • 确保Image的scaledToFit()正确保持正方形比例,外层frame(height:300)会让图片宽度自适应,保持2010×2010的原始比例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 07:31:19