如何在UIImage上实现MapKit同款长按放置大头针、添加Annotation功能
解决方案
你没法直接复用MapKit的Annotation相关能力到UIImageView上,需要自己实现一套类似的交互逻辑,核心只需要替换坐标转换、视图添加两部分代码即可,和你现有MapKit的实现逻辑几乎一致。
1. 先定义大头针数据模型
用来存储每个大头针的位置、标题、备注信息,和MKPointAnnotation功能对齐:
struct ImageAnnotation { let position: CGPoint // 对应UIImageView上的位置 var title: String? var subtitle: String? }
2. 给UIImageView添加长按交互
替换原有绑定在MapView上的长按手势,绑定到你的image属性上,处理长按逻辑:
首先在你的ViewController里新增两个属性:
// 存储所有添加的大头针数据 var annotations: [ImageAnnotation] = [] // 模拟MapKit的代理回调,可选,用来对齐你原有MapKit的使用习惯 var didSelectAnnotation: ((ImageAnnotation) -> Void)?
然后在viewDidLoad里添加UIImageView的长按手势:
// 给UIImageView加长按手势 let imageLongPress = UILongPressGestureRecognizer(target: self, action: #selector(handleImageLongPress(_:))) imageLongPress.minimumPressDuration = 0.5 image.isUserInteractionEnabled = true // 必须开启,UIImageView默认关闭交互 image.addGestureRecognizer(imageLongPress)
实现长按处理方法:
@objc func handleImageLongPress(_ gesture: UILongPressGestureRecognizer) { guard gesture.state == .began else { return } // 获取长按在UIImageView上的位置 let point = gesture.location(in: image) // 如果需要适配UIImageView的contentMode,获取实际对应图片上的坐标可以用以下代码,不需要的话直接用上面的point即可 /* let imageSize = image.image?.size ?? .zero let viewSize = image.bounds.size let scale = max(viewSize.width / imageSize.width, viewSize.height / imageSize.height) let imageRect = CGRect( x: (viewSize.width - imageSize.width * scale) / 2, y: (viewSize.height - imageSize.height * scale) / 2, width: imageSize.width * scale, height: imageSize.height * scale ) guard imageRect.contains(point) else { return } let realImagePoint = CGPoint( x: (point.x - imageRect.minX) / scale, y: (point.y - imageRect.minY) / scale ) */ // 创建大头针视图,你可以自定义样式 let pinView = UIImageView(image: UIImage(systemName: "mappin")) pinView.tintColor = .red pinView.center = point pinView.bounds = CGRect(x: 0, y: 0, width: 30, height: 30) // 给大头针加点击手势 let tap = UITapGestureRecognizer(target: self, action: #selector(handlePinTap(_:))) pinView.addGestureRecognizer(tap) pinView.isUserInteractionEnabled = true image.addSubview(pinView) // 存储大头针数据 let annotation = ImageAnnotation( position: point, title: "位置: \(String(format: "%.1f", point.x)), \(String(format: "%.1f", point.y))", subtitle: "自定义备注" ) annotations.append(annotation) // 绑定数据到视图,方便点击时获取 pinView.tag = annotations.count - 1 }
3. 实现大头针点击交互
@objc func handlePinTap(_ gesture: UITapGestureRecognizer) { guard let pinView = gesture.view as? UIImageView, pinView.tag < annotations.count else { return } let annotation = annotations[pinView.tag] // 处理点击逻辑,和你原来mapView的didSelect逻辑一致 print("选中大头针:\(annotation.title ?? ""),备注:\(annotation.subtitle ?? "")") // 你可以在这里弹出弹窗修改备注,更新annotations里的数据即可 }
额外适配(可选)
如果你放在UIImageView上的是地图截图,想要把图片上的点对应到实际经纬度,只需要提前拿到图片四个角对应的经纬度,做线性映射即可,完全可以复用你原来的经纬度展示逻辑。
内容的提问来源于stack exchange,提问作者George ozzy
相关产品推荐
相关产品推荐

