iOS(UIKit)中如何按百分比显示并填充SVG国家/区域地图
解决方案:iOS 分级统计图(Choropleth Map)实现
一、基于 SVG 的精准填充方案(解决你遇到的颜色修改问题)
1. SVGKit 实操步骤
核心思路是通过 SVG 中区域的唯一 id 匹配数据,遍历图层修改对应 CAShapeLayer 的填充色:
- 先确保你的 SVG 文件中,每个需要填充的区域都带有唯一
id(比如<path id="london" d="..."/>) - 加载并修改颜色的代码示例:
import SVGKit // 加载 SVG 文件 let svgURL = Bundle.main.url(forResource: "uk-map", withExtension: "svg")! let svgImage = SVGKImage(contentsOf: svgURL) let svgView = SVGKFastImageView(image: svgImage) svgView.frame = CGRect(x: 20, y: 20, width: view.bounds.width-40, height: view.bounds.height-40) view.addSubview(svgView) // 模拟数据:区域 id -> 百分比 let regionData = ["london": 85, "manchester": 60, "birmingham": 45] // 百分比转颜色的映射函数 func getColor(for percentage: Int) -> UIColor { switch percentage { case 0..<30: return UIColor(red: 0.8, green: 0.8, blue: 0.8, alpha: 1) case 30..<60: return UIColor(red: 1, green: 0.6, blue: 0, alpha: 1) case 60...100: return UIColor(red: 0.8, green: 0, blue: 0, alpha: 1) default: return .gray } } // 递归遍历图层,修改对应区域颜色 func updateLayerColors(layer: CALayer) { if let shapeLayer = layer as? CAShapeLayer, let regionId = shapeLayer.name { if let pct = regionData[regionId] { shapeLayer.fillColor = getColor(for: pct).cgColor shapeLayer.strokeColor = UIColor.black.cgColor shapeLayer.lineWidth = 0.5 } } layer.sublayers?.forEach(updateLayerColors) } // 执行颜色更新 updateLayerColors(layer: svgView.layer)
注意:SVGKit 会自动将 SVG 元素的
id赋值给CAShapeLayer的name属性,这是匹配的关键。
2. SwiftSVG 进阶用法
如果用 SwiftSVG,可直接解析生成图层后遍历修改:
import SwiftSVG let svgView = UIView(frame: CGRect(x: 20, y: 20, width: view.bounds.width-40, height: view.bounds.height-40)) view.addSubview(svgView) SVGParser.parse(url: Bundle.main.url(forResource: "uk-map", withExtension: "svg")!) { layer in layer.frame = svgView.bounds svgView.layer.addSublayer(layer) // 复用上面的 regionData、getColor、updateLayerColors 函数 updateLayerColors(layer: layer) }
二、不使用 SVG 的替代方案
1. MapKit 自定义多边形绘制
适合国家/大洲级的粗粒度地图,通过经纬度坐标生成 MKPolygon 并设置样式:
import MapKit class MapVC: UIViewController, MKMapViewDelegate { @IBOutlet weak var mapView: MKMapView! let regionData = ["london": 85] override func viewDidLoad() { super.viewDidLoad() mapView.delegate = self // 示例:伦敦区域的经纬度轮廓(实际需导入完整坐标数据) let londonCoords = [ CLLocationCoordinate2D(latitude: 51.5074, longitude: -0.1278), // 更多坐标点... ] let londonPolygon = MKPolygon(coordinates: londonCoords, count: londonCoords.count) londonPolygon.title = "london" mapView.addOverlay(londonPolygon) } func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { guard let polygon = overlay as? MKPolygon else { return MKOverlayRenderer() } let renderer = MKPolygonRenderer(polygon: polygon) if let regionName = polygon.title, let pct = regionData[regionName] { renderer.fillColor = getColor(for: pct).withAlphaComponent(0.7) renderer.strokeColor = .black renderer.lineWidth = 1 } return renderer } }
2. 专业地图可视化库推荐
- Mapbox iOS SDK:支持加载自定义矢量瓦片(可将 SVG 转换为矢量瓦片),能动态配置区域样式,适合专业级需求。
- Charts:虽主打图表,但可结合自定义
UIBezierPath实现轻量化的分级地图。
三、核心注意事项
- 确保区域标识(SVG 的
id或 MapKit 多边形的title)与数据字典的 Key 完全匹配,这是动态填充的基础。 - 颜色映射尽量采用渐变或区分度高的色系,提升可读性。
- 若区域数量较多,建议提前缓存图层引用,避免频繁遍历影响性能。
内容的提问来源于stack exchange,提问作者Guillaume B
相关产品推荐
相关产品推荐

