1. 10.地图多边形实现

1.1.1. 十六、地图多边形实现

第1步:新增地图覆盖物协议、地图覆盖物Renderer协议

OverlayProtocol(地图覆盖物协议)、OverlayRendererProtocol(地图覆盖物Renderer协议)

/// 地图覆盖物协议,所有地图的覆盖物需要实现
public protocol OverlayProtocol: NSObjectProtocol {

    /// 具体地图覆盖物实现
    var overlayImpl: Any? { get }

    /// 构造方法
    /// - Parameter annotationImpl: 具体地图覆盖物实现
    init(overlayImpl: Any?)

}
/// 地图覆盖物Renderer协议
public protocol OverlayRendererProtocol: NSObjectProtocol {

    /// 填充颜色,默认是kMAOverlayRendererDefaultFillColor
    var fillColor: UIColor { get set }

    /// 笔触颜色,默认是kMAOverlayRendererDefaultStrokeColor
    var strokeColor: UIColor { get set }

    ///笔触宽度, 单位屏幕点坐标,默认是0
    var lineWidth: CGFloat { get set }

    /// 具体地图标注view实现
    var overRendererImpl: Any? { get }

    /// 构造方法
    /// - Parameter overRendererImpl: 具体地图覆盖物Renderer实现
    init(overRendererImpl: Any?)

}

第2步:新增地图多边形实现、地图多边形Renderer实现

GaodePolygon(高德地图多边形)、GaodePolygonRenderer(高德地图多边形Renderer)

BaiduPolygon(百度地图多边形)、BaiduPolygonRenderer(百度地图多边形Renderer)

Polygon(通用多边形)、PolygonRenderer(通用多边形Renderer)

/// 高德地图多边形
public class GaodePolygon: MAPolygon {

    /// 聚合多边形区域l
    weak var polygon: Polygon?
}
/// 高德地图多边形Renderer
public class GaodePolygonRenderer: MAPolygonRenderer {

}
/// 百度多边形
public class BaiduPolygon: BMKPolygon {

    /// 聚合多边形区域l
    weak var polygon: Polygon?
}
/// 百度多边形Renderer
public class BaiduPolygonRenderer: BMKPolygonView {

}
/// 通用多边形
public class Polygon: NSObject, OverlayProtocol {

    /// 具体地图覆盖物实现
    private(set) public var overlayImpl: Any?

    /// 高德覆盖物
    private var gaodePolygon: GaodePolygon? {
        if let overlay = overlayImpl as? GaodePolygon {
            return overlay
        }
        return nil
    }

    /// 百度覆盖物
    private var baiduPolygon: BaiduPolygon? {
        if let overlay = overlayImpl as? BaiduPolygon {
            return overlay
        }
        return nil
    }

    /// 构造方法
    /// - Parameter overlayImpl: 具体地图覆盖物实现
    public required init(overlayImpl: Any?) {
        super.init()
        self.overlayImpl = overlayImpl
        gaodePolygon?.polygon = self
        baiduPolygon?.polygon = self
    }

}
/// 通用多边形Renderer
public class PolygonRenderer: NSObject, OverlayRendererProtocol {

    /// 填充颜色,默认是kMAOverlayRendererDefaultFillColor
    public var fillColor: UIColor {
        get {
            if let overRenderer = gaodeOverRenderer {
                return overRenderer.fillColor
            }
            if let overRenderer = baiduOverRenderer {
                return overRenderer.fillColor
            }
            return .red
        }
        set {
            if let overRenderer = gaodeOverRenderer {
                overRenderer.fillColor = newValue
            }
            if let overRenderer = baiduOverRenderer {
                overRenderer.fillColor = newValue
            }
        }
    }

    /// 笔触颜色,默认是kMAOverlayRendererDefaultStrokeColor
    public var strokeColor: UIColor {
        get {
            if let overRenderer = gaodeOverRenderer {
                return overRenderer.strokeColor
            }
            if let overRenderer = baiduOverRenderer {
                return overRenderer.strokeColor
            }
            return .red
        }
        set {
            if let overRenderer = gaodeOverRenderer {
                overRenderer.strokeColor = newValue
            }
            if let overRenderer = baiduOverRenderer {
                overRenderer.strokeColor = newValue
            }
        }
    }

    ///笔触宽度, 单位屏幕点坐标,默认是0
    public var lineWidth: CGFloat {
        get {
            if let overRenderer = gaodeOverRenderer {
                return overRenderer.lineWidth
            }
            if let overRenderer = baiduOverRenderer {
                return overRenderer.lineWidth
            }
            return 0
        }
        set {
            if let overRenderer = gaodeOverRenderer {
                overRenderer.lineWidth = newValue
            }
            if let overRenderer = baiduOverRenderer {
                overRenderer.lineWidth = newValue
            }
        }
    }

    /// 具体地图覆盖物实现
    public private(set) var overRendererImpl: Any?

    /// 高德地图覆盖物
    private var gaodeOverRenderer: GaodePolygonRenderer? {
        return overRendererImpl as? GaodePolygonRenderer
    }

    /// 百度地图覆盖物
    private var baiduOverRenderer: BaiduPolygonRenderer? {
        return overRendererImpl as? BaiduPolygonRenderer
    }

    /// 构造方法
    /// - Parameter overRendererImpl: 具体地图覆盖物Renderer实现
    public required init(overRendererImpl: Any?) {
        self.overRendererImpl = overRendererImpl
    }

}

第3步:地图工厂标准修改及实现

/// 地图工厂标准
public protocol MapFactoryProtocol: NSObjectProtocol {

    ......

    /// 根据经纬度坐标数据生成闭合多边形
    /// - Parameters:
    ///   - coordinates: 经纬度坐标点数据,coords对应的内存会拷贝,调用者负责该内存的释放
    ///   - count: 经纬度坐标点数组个数
    /// - Returns: 新生成的多边形
    func getPolygon(coordinates: UnsafeMutablePointer<CLLocationCoordinate2D>, count: UInt) -> Polygon

    /// 根据指定的多边形生成一个多边形Renderer
    /// - Parameter overlay: 指定的多边形数据对象
    /// - Returns: 新生成的多边形Renderer
    func getPolygonRenderer(overlay: OverlayProtocol) -> OverlayRendererProtocol
}
/// 高德地图工厂
class GaodeMapFactory: NSObject, MapFactoryProtocol {

    ......

    /// 根据经纬度坐标数据生成闭合多边形
    /// - Parameters:
    ///   - coordinates: 经纬度坐标点数据,coords对应的内存会拷贝,调用者负责该内存的释放
    ///   - count: 经纬度坐标点数组个数
    /// - Returns: 新生成的多边形
    func getPolygon(coordinates: UnsafeMutablePointer<CLLocationCoordinate2D>, count: UInt) -> Polygon {
        let polygonImpl = GaodePolygon(coordinates: coordinates, count: count)
        return Polygon(overlayImpl: polygonImpl)
    }

    /// 根据指定的多边形生成一个多边形Renderer
    /// - Parameter overlay: 指定的多边形数据对象
    /// - Returns: 新生成的多边形Renderer
    func getPolygonRenderer(overlay: OverlayProtocol) -> OverlayRendererProtocol {

        var polygonImpl = GaodePolygon()
        if let overlayImplParam = overlay.overlayImpl as? GaodePolygon {
            polygonImpl = overlayImplParam
        }
        let polygonRendererImpl = GaodePolygonRenderer(overlay: polygonImpl)
        return PolygonRenderer(overRendererImpl: polygonRendererImpl)
    }
}
/// 百度地图工厂
class BaiduMapFactory: NSObject, MapFactoryProtocol {
    ......

    /// 根据经纬度坐标数据生成闭合多边形
    /// - Parameters:
    ///   - coordinates: 经纬度坐标点数据,coords对应的内存会拷贝,调用者负责该内存的释放
    ///   - count: 经纬度坐标点数组个数
    /// - Returns: 新生成的多边形
    func getPolygon(coordinates: UnsafeMutablePointer<CLLocationCoordinate2D>, count: UInt) -> Polygon {
        let polygonImpl = BaiduPolygon(coordinates: coordinates, count: count)
        return Polygon(overlayImpl: polygonImpl)
    }

    /// 根据指定的多边形生成一个多边形Renderer
    /// - Parameter overlay: 指定的多边形数据对象
    /// - Returns: 新生成的多边形Renderer
    func getPolygonRenderer(overlay: OverlayProtocol) -> OverlayRendererProtocol {

        var polygonImpl = BaiduPolygon()
        if let overlayImplParam = overlay.overlayImpl as? BaiduPolygon {
            polygonImpl = overlayImplParam
        }
        let polygonRendererImpl = BaiduPolygonRenderer(overlay: polygonImpl)
        return PolygonRenderer(overRendererImpl: polygonRendererImpl)
    }
}

第4步:地图协议修改及实现

/// 地图协议
public protocol MapViewProtocol: NSObjectProtocol {

    ......

    /// 向地图窗口添加一组Overlay,需要实现MAMapViewDelegate的-mapView:rendererForOverlay:函数来生成标注对应的Renderer
    /// - Parameter overlays: 要添加的overlay数组
    func addOverlays(overlays: [OverlayProtocol])

    /// 设置地图使其可以显示数组中所有的overlay, 如果数组中只有一个则直接设置地图中心为overlay的位置。
    /// - Parameters:
    ///   - overlays: 需要显示的overlays
    ///   - animated: 是否执行动画
    func showOverlays(overlays: [OverlayProtocol], animated: Bool)
}
/// 高德地图
class GaodeMapView: NSObject, MapViewProtocol {
    ......

    /// 向地图窗口添加一组Overlay,需要实现MAMapViewDelegate的-mapView:rendererForOverlay:函数来生成标注对应的Renderer
    /// - Parameter overlays: 要添加的overlay数组
    func addOverlays(overlays: [OverlayProtocol]) {
        var overlayImpls: [Any] = []
        for overlay in overlays {
            if let overlayImpl = overlay.overlayImpl {
                overlayImpls.append(overlayImpl)
            }
        }
        mapView.addOverlays(overlayImpls)
    }

    /// 设置地图使其可以显示数组中所有的overlay, 如果数组中只有一个则直接设置地图中心为overlay的位置。
    /// - Parameters:
    ///   - overlays: 需要显示的overlays
    ///   - animated: 是否执行动画
    func showOverlays(overlays: [OverlayProtocol], animated: Bool) {
        var overlayImpls: [Any] = []
        for overlay in overlays {
            if let overlayImpl = overlay.overlayImpl {
                overlayImpls.append(overlayImpl)
            }
        }
        mapView.showOverlays(overlayImpls, animated: animated)
    }
}
/// 高德地图代理实现
class MAMapViewDelegateImpl: NSObject, MAMapViewDelegate {

    ......

    func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
        if let polygonOverlay = overlay as? GaodePolygon, let poly = polygonOverlay.polygon {
            if let polygonRenderer = delegate?.mapView(mapViewProtocol, rendererFor: poly)?.overRendererImpl as? MAPolygonRenderer {
                return polygonRenderer
            }
        }
        return nil
    }
}
/// 百度地图
class BaiduMapView: NSObject, MapViewProtocol {
    ......

    /// 向地图窗口添加一组Overlay,需要实现MAMapViewDelegate的-mapView:rendererForOverlay:函数来生成标注对应的Renderer
    /// - Parameter overlays: 要添加的overlay数组
    func addOverlays(overlays: [OverlayProtocol]) {
        var overlayImpls: [BMKOverlay] = []
        for overlay in overlays {
            if let overlayImpl = overlay.overlayImpl as? BMKOverlay {
                overlayImpls.append(overlayImpl)
            }
        }
        mapView.addOverlays(overlayImpls)
    }

    /// 设置地图使其可以显示数组中所有的overlay, 如果数组中只有一个则直接设置地图中心为overlay的位置。
    /// - Parameters:
    ///   - overlays: 需要显示的overlays
    ///   - animated: 是否执行动画
    func showOverlays(overlays: [OverlayProtocol], animated: Bool) {
        var overlayImpls: [BMKOverlay] = []
        for overlay in overlays {
            if let overlayImpl = overlay.overlayImpl as? BMKOverlay {
                overlayImpls.append(overlayImpl)
            }
        }
    }
}
/// 百度地图代理实现
class BMKMapViewDelegateImpl: NSObject, BMKMapViewDelegate {

    ......

    func mapView(_ mapView: BMKMapView!, viewFor overlay: BMKOverlay!) -> BMKOverlayView! {
        if let polygonOverlay = overlay as? BaiduPolygon, let poly = polygonOverlay.polygon {
            if let polygonRenderer = delegate?.mapView(mapViewProtocol, rendererFor: poly)?.overRendererImpl as? BMKPolygonView {
                return polygonRenderer
            }
        }
        return nil
    }

}

第5步:测试页面

class PolygonViewController: UIViewController {

    /// 地图工厂
    private lazy var factory: MapFactoryProtocol = {
        let factory = MapEngine.shared.getFactory()!
        return factory
    }()

    /// 地图实例
    private lazy var mapView: MapViewProtocol = {
        // 显示地图
        let mapView = factory.getMapView(frame: view.bounds)
        // 设置代理
        mapView.delegate = self
        // 显示用户定位(放在设置代理之后,确保可以调用locationManager.requestAlwaysAuthorization())
        mapView.showsUserLocation = true
        // 跟踪模式
        mapView.userTrackingMode = .followWithHeading
        // 设置缩放
        mapView.zoomLevel = 16
        return mapView
    }()

    /// 标注数组
    private lazy var polygons: Array<Polygon> = {
        var polygons = Array<Polygon>()

        var polygonCoordinates: [CLLocationCoordinate2D] = [
            CLLocationCoordinate2D(latitude: 39.781892, longitude: 116.283413),
            CLLocationCoordinate2D(latitude: 39.787600, longitude: 116.391842),
            CLLocationCoordinate2D(latitude: 39.733187, longitude: 116.417932),
            CLLocationCoordinate2D(latitude: 39.704653, longitude: 116.338255)]

        let polygon = factory.getPolygon(coordinates: &polygonCoordinates, count: UInt(polygonCoordinates.count))
        polygons.append(polygon)

        return polygons
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white
        view.addSubview(mapView.getView())

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        mapView.addOverlays(overlays: polygons)
        mapView.showOverlays(overlays: polygons, animated: false)
    }

}

extension PolygonViewController: MapViewDelegateProtocol {

    func mapView(_ mapView: MapViewProtocol, rendererFor overlay: OverlayProtocol) -> OverlayRendererProtocol? {

        if overlay.isKind(of: Polygon.self) {

            let renderer = factory.getPolygonRenderer(overlay: overlay)
            renderer.lineWidth = 8.0
            renderer.strokeColor = UIColor.magenta
            renderer.fillColor = UIColor.yellow.withAlphaComponent(0.4)

            return renderer
        }
        return nil
    }
}

results matching ""

    No results matching ""