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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:09:04