Swift:MKAnnotation选中/取消选中时尺寸变化动画异常问题
解决MKMapView标注尺寸动画时的位置偏移问题
看起来你遇到的问题是因为直接修改MKAnnotationView的frame时,没考虑地图坐标系的特殊性——MKMapView的视图坐标系会随地图缩放、平移动态变化,直接对frame做动画会导致系统计算的位置出现偏差,从而出现标注从屏幕外滑入的奇怪效果。
这里给你两种靠谱的解决方案,优先推荐第一种,简单又高效:
方案一:使用CGAffineTransform做缩放动画
这种方式基于标注视图自身的中心点做缩放,完全不会改变视图位置,动画效果自然流畅,不会出现偏移问题。你只需要在标注选中和取消选中的代理方法里添加动画即可:
// 标注选中时放大 func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) { UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5) { view.transform = CGAffineTransform(scaleX: 1.2, y: 1.2) } } // 标注取消选中时恢复原尺寸 func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) { UIView.animate(withDuration: 0.3) { view.transform = .identity } }
我还加了弹簧动画参数,让缩放效果更有弹性,你可以根据需求调整
usingSpringWithDamping和initialSpringVelocity的值,或者去掉弹簧效果直接用基础动画。
方案二:基于中心位置修改frame(不推荐,但适合特殊需求)
如果你因为某些原因必须修改frame,那一定要保证动画过程中标注的中心位置不变,避免坐标系偏移问题。可以先记录下当前视图的中心,再计算新的frame:
首先给CGRect加个扩展,方便根据中心和尺寸创建矩形:
extension CGRect { init(center: CGPoint, size: CGSize) { let originX = center.x - size.width / 2 let originY = center.y - size.height / 2 self.init(origin: CGPoint(x: originX, y: originY), size: size) } }
然后在代理方法里使用这个扩展来做动画:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) { let originalCenter = view.center let originalSize = view.frame.size let newSize = CGSize(width: originalSize.width * 1.2, height: originalSize.height * 1.2) UIView.animate(withDuration: 0.3) { view.frame = CGRect(center: originalCenter, size: newSize) } } func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) { let originalCenter = view.center let originalSize = CGSize(width: 你的原始宽度, height: 你的原始高度) UIView.animate(withDuration: 0.3) { view.frame = CGRect(center: originalCenter, size: originalSize) } }
关键注意点
- 不要在
mapView(_:viewFor:)方法里做动画!这个方法是用来创建和配置标注视图的,此时视图还没有被正确添加到地图的布局体系中,做动画必然会出现位置错误。一定要在didSelect和didDeselect代理方法里执行动画,这时候视图已经正确布局在地图上了。 - 优先使用
transform方案,不仅代码更简洁,而且系统对transform动画有优化,性能更好,也不会出现坐标系相关的问题。
内容的提问来源于stack exchange,提问作者Pobbin
相关产品推荐
相关产品推荐

