iOS MapBox SDK:如何实现MGLPolygon圆形覆盖层的淡入淡出效果
嘿,刚好之前做过类似的需求,给你两个靠谱的方案,都是基于MapBox iOS SDK的特性来实现MGLPolygon的淡入淡出效果:
方案一:使用MapBox样式层(推荐)
直接用MGLPolygon作为Annotation的方式,在动画灵活性上不如样式层——样式层是MapBox渲染管线优化过的,性能更好,尤其是地图频繁缩放平移时表现更稳定,也更适合做属性动画。
实现步骤:
将多边形添加到地图数据源:
先把你生成的MGLPolygon关联到MGLShapeSource,再把数据源添加到地图样式中:// 假设你已经生成了固定半径的circlePolygon let shapeSource = MGLShapeSource(identifier: "fixed-radius-circle-source", shape: circlePolygon, options: nil) mapView.style?.addSource(shapeSource)创建填充样式层并设置初始状态:
创建MGLFillStyleLayer关联数据源,初始设为完全透明,方便触发淡入:let fillLayer = MGLFillStyleLayer(identifier: "fixed-radius-circle-fill", source: shapeSource) fillLayer.fillColor = NSExpression(forConstantValue: UIColor.blue.withAlphaComponent(1)) // 基础色设为不透明,用opacity控制透明度 fillLayer.fillOpacity = NSExpression(forConstantValue: 0) // 初始透明 mapView.style?.addLayer(fillLayer)添加淡入/淡出动画:
用Core Animation给样式层的fillOpacity属性加动画:// 淡入动画 func fadeInCircle() { guard let fillLayer = mapView.style?.layer(withIdentifier: "fixed-radius-circle-fill") as? MGLFillStyleLayer else { return } let fadeInAnim = CABasicAnimation(keyPath: "fillOpacity") fadeInAnim.fromValue = 0 fadeInAnim.toValue = 0.3 // 目标透明度,可按需调整 fadeInAnim.duration = 0.5 // 动画时长,0.5秒是自然的过渡速度 fadeInAnim.fillMode = .forwards fadeInAnim.isRemovedOnCompletion = false fillLayer.add(fadeInAnim, forKey: "circleFadeIn") } // 淡出动画(结束后可选择移除图层) func fadeOutCircle() { guard let fillLayer = mapView.style?.layer(withIdentifier: "fixed-radius-circle-fill") as? MGLFillStyleLayer else { return } let fadeOutAnim = CABasicAnimation(keyPath: "fillOpacity") fadeOutAnim.fromValue = 0.3 fadeOutAnim.toValue = 0 fadeOutAnim.duration = 0.5 fadeOutAnim.fillMode = .forwards fadeOutAnim.isRemovedOnCompletion = false // 动画结束后移除图层 fadeOutAnim.delegate = self fillLayer.add(fadeOutAnim, forKey: "circleFadeOut") } // 实现CAAnimationDelegate移除图层 func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { if anim == mapView.style?.layer(withIdentifier: "fixed-radius-circle-fill")?.animation(forKey: "circleFadeOut") { mapView.style?.removeLayer(mapView.style!.layer(withIdentifier: "fixed-radius-circle-fill")!) mapView.style?.removeSource(mapView.style!.source(withIdentifier: "fixed-radius-circle-source")!) } }
方案二:自定义MGLPolygonRenderer(兼容原有Annotation方式)
如果你们已经习惯用addAnnotation的方式添加多边形,不想改动现有数据源逻辑,可以通过自定义渲染器来控制透明度动画。
实现步骤:
自定义多边形渲染器:
创建继承自MGLPolygonRenderer的类,通过变量控制绘制时的透明度:class AnimatedPolygonRenderer: MGLPolygonRenderer { var currentAlpha: CGFloat = 0 { didSet { setNeedsDisplay() // 透明度变化时触发重绘 } } override func draw(_ mapRect: MGLMapRect, zoomScale: MGLZoomScale, in context: CGContext) { context.setAlpha(currentAlpha) super.draw(mapRect, zoomScale: zoomScale, in: context) } }在地图代理中返回自定义渲染器:
实现mapView(_:rendererFor:)方法,给你的MGLPolygon返回自定义渲染器:func mapView(_ mapView: MGLMapView, rendererFor annotation: MGLAnnotation) -> MGLAnnotationRenderer? { guard let polygon = annotation as? MGLPolygon else { return nil } let renderer = AnimatedPolygonRenderer(annotation: polygon) renderer.fillColor = UIColor.blue.withAlphaComponent(1) // 基础色设为不透明,用currentAlpha控制最终透明度 renderer.strokeColor = UIColor.blue renderer.lineWidth = 2 return renderer }触发淡入/淡出动画:
通过UIView动画更新渲染器的currentAlpha:// 淡入 func fadeInCircleAnnotation(polygon: MGLPolygon) { guard let renderer = mapView.renderer(for: polygon) as? AnimatedPolygonRenderer else { return } UIView.animate(withDuration: 0.5) { renderer.currentAlpha = 0.3 } } // 淡出并移除Annotation func fadeOutCircleAnnotation(polygon: MGLPolygon) { guard let renderer = mapView.renderer(for: polygon) as? AnimatedPolygonRenderer else { return } UIView.animate(withDuration: 0.5, animations: { renderer.currentAlpha = 0 }) { _ in self.mapView.removeAnnotation(polygon) } }
额外注意事项
- 动画结束后,如果不需要这个圆形覆盖层了,记得及时移除对应的样式层/数据源,或者Annotation,避免不必要的内存占用。
- 淡入淡出的
duration可以根据需求调整,0.5秒是比较自然的过渡速度,你可以改成0.3秒(快速)或1秒(平缓)。 - 如果需要重复触发动画,注意先移除之前的动画(比如用
fillLayer.removeAnimation(forKey: "circleFadeIn")),避免动画叠加导致的异常。
内容的提问来源于stack exchange,提问作者standers
相关产品推荐
相关产品推荐

