SwiftUI中MapKit的OnTapGesture导致UserLocationButton失效
问题代码
struct AddRoomMap: View { @State private var position: MapCameraPosition = initialPosition @State private var selectedRoom: String? var body: some View { MapReader { reader in Map(initialPosition: initialPosition, selection: $selectedRoom){ UserAnnotation() } .onTapGesture(perform: { screenCoord in let pinLocation = reader.convert(screenCoord, from: .local) print(pinLocation ) }) .mapControls({ MapUserLocationButton() }) .onAppear{ CLLocationManager().requestAlwaysAuthorization() } } } }
问题描述
在SwiftUI的AddRoomMap视图中,使用MapReader和onTapGesture获取地图点击的地理位置时,MapUserLocationButton出现功能异常:点击该按钮时,地图会跳转至按钮后方的区域,而非用户的实际位置。
问题原因
直接给Map添加onTapGesture会拦截MapControls内部按钮的点击事件,导致按钮的原生定位功能被覆盖,反而触发了地图的点击跳转逻辑。
解决方法
方法一:使用Map原生的onTap修饰符(iOS 17+推荐)
iOS 17及以上版本的Map组件提供了原生的onTap回调,能直接获取点击的地理位置,且不会干扰MapControls的交互,代码更简洁:
struct AddRoomMap: View { @State private var position: MapCameraPosition = initialPosition @State private var selectedRoom: String? var body: some View { Map(initialPosition: initialPosition, selection: $selectedRoom){ UserAnnotation() } // 用Map自带的onTap替代MapReader+onTapGesture .onTap { _, coordinate in print(coordinate) // 直接拿到点击的地理坐标 } .mapControls { MapUserLocationButton() } .onAppear{ CLLocationManager().requestAlwaysAuthorization() } } }
方法二:调整层级兼容iOS 16及以下
如果需要兼容低版本,可将MapControls放在ZStack的上层,避免被MapReader的手势拦截:
struct AddRoomMap: View { @State private var position: MapCameraPosition = initialPosition @State private var selectedRoom: String? var body: some View { ZStack { MapReader { reader in Map(initialPosition: initialPosition, selection: $selectedRoom){ UserAnnotation() } .onTapGesture(perform: { screenCoord in let pinLocation = reader.convert(screenCoord, from: .local) print(pinLocation ) }) } // 将定位按钮放在上层,避免手势拦截 VStack { Spacer() HStack { Spacer() MapUserLocationButton() .padding() } } } .onAppear{ CLLocationManager().requestAlwaysAuthorization() } } }
内容的提问来源于stack exchange,提问作者qqqwerqqq
相关产品推荐
相关产品推荐

