Yandex MapKit iOS:点击YMKPlacemarkMapObject动画无效及imageView访问问题
解决YMKPlacemarkMapObject点击动画不生效的问题
首先得搞清楚你的动画没起作用的核心原因:UIView.animate()是针对UIKit组件的属性动画设计的,但Yandex Maps的YMKPlacemarkMapObject的iconStyle变化并不受UIKit动画系统管控——Yandex Maps SDK是自己负责地图元素的渲染逻辑,所以直接在动画闭包里修改iconStyle的scale不会产生平滑的动画效果。
另外你提到的访问imageView的需求,Yandex Maps iOS SDK确实没有提供直接访问地标底层UIImageView的API,它的渲染逻辑是封装起来的,和Google Maps的实现思路不同,所以得换个方式实现缩放动画。
可行解决方案1:手动插值+逐帧更新
我们可以通过手动计算scale的中间值,用CADisplayLink逐帧更新iconStyle,模拟弹簧动画的效果:
func onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) -> Bool { guard let placemark = mapObject as? YMKPlacemarkMapObject else { return false } // 保存原始图标样式,避免动画后丢失其他属性 let originalStyle = placemark.iconStyle let targetScale: CGFloat = 2.0 let totalDuration: TimeInterval = 1.0 let dampingRatio: CGFloat = 0.5 var startTime: TimeInterval? let displayLink = CADisplayLink(target: self, selector: #selector(updatePlacemarkScale(_:))) @objc private func updatePlacemarkScale(_ link: CADisplayLink) { guard let startTime = startTime else { startTime = link.timestamp return } let elapsedTime = link.timestamp - startTime if elapsedTime >= totalDuration { link.invalidate() // 动画结束后恢复原始样式 placemark.setIconStyleWith(originalStyle) return } // 用UIViewPropertyAnimator计算弹簧动画的进度值 let animator = UIViewPropertyAnimator(duration: totalDuration, dampingRatio: dampingRatio) animator.fractionComplete = CGFloat(elapsedTime / totalDuration) // 根据进度计算当前缩放比例 let currentScale = originalStyle.scale + (targetScale - originalStyle.scale) * animator.fractionComplete let animatedStyle = YMKIconStyle() animatedStyle.scale = currentScale // 复制原始样式的其他属性,保证图标样式完整 animatedStyle.iconImage = originalStyle.iconImage animatedStyle.rotation = originalStyle.rotation animatedStyle.zIndex = originalStyle.zIndex placemark.setIconStyleWith(animatedStyle) } displayLink.add(to: .main, forMode: .common) return true }
可行解决方案2:使用Yandex Maps内置动画API(版本依赖)
如果你的Yandex Maps SDK版本较新,可能支持YMKAnimation相关接口,可以直接用它实现弹簧动画:
func onMapObjectTap(with mapObject: YMKMapObject, point: YMKPoint) -> Bool { guard let placemark = mapObject as? YMKPlacemarkMapObject else { return false } let originalStyle = placemark.iconStyle // 创建放大后的样式 let enlargedStyle = YMKIconStyle() enlargedStyle.scale = 2.0 enlargedStyle.iconImage = originalStyle.iconImage enlargedStyle.rotation = originalStyle.rotation enlargedStyle.zIndex = originalStyle.zIndex // 执行放大的弹簧动画 placemark.setIconStyleWith(enlargedStyle, animation: YMKAnimation(duration: 0.5, type: .spring(dampingRatio: 0.5))) // 延迟后恢复原始大小 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { placemark.setIconStyleWith(originalStyle, animation: YMKAnimation(duration: 0.5, type: .spring(dampingRatio: 0.5))) } return true }
注意:这个方案需要确认你的SDK版本是否支持YMKAnimation,部分旧版本可能没有这个接口。
总结
- 不能用
UIView.animate()直接修改YMKIconStyle,因为Yandex Maps的渲染逻辑独立于UIKit动画系统 - Yandex Maps SDK不暴露底层
UIImageView,必须通过修改iconStyle并配合逐帧更新或内置动画API实现效果 - 修改
iconStyle时记得复制所有属性,避免只改scale导致其他样式丢失
内容的提问来源于stack exchange,提问作者serdar aylanc
相关产品推荐
相关产品推荐

