swift-调用高德sdk填充行政区域,并实现区分填充区域内外点击动作

老规矩先上效果图(北京的朝阳区):

在这里插入图片描述
此图是从https://lbs.amap.com/api/javascript-api/example/district-search/draw-district-boundaries这个网站截得,手机真机测试的效果和颜色和这个一样,另外就是再加上点击蓝色区域内和蓝色区域外会有toast弹窗提示。
先描述一下情况: 这几天正好做实验室的一个小项目app(也就是仅供学习那种。。。)需要的一个功能是在地图上进行填充需要的行政区域,也就是行政区划填充,并且要实现能够区分点击填充区域内外的动作。但是从网上大多是画轮廓线的,少有的还是oc写的,折腾了好久好久终于出效果了,特此来记录一下,看看能不能帮助需要的朋友少走弯路。
一开始看到这个博主的代码和思路:

https://blog.csdn.net/Felicity294250051/article/details/82801137

无奈本人太菜,给的程序不全,并且好多函数功能没讲清楚(反正我是没看懂),但是对理解代码还是帮助蛮大的(此处表示感谢博主
于是还是得又从官方给的demo下手,倒是有画轮廓线的,也有画多边形面的,记得网上就有一些根据现成的几个经纬度点来画多边形面,给几个链接:(反正当时搜了很多到处看,现在能找到可能有帮助的就这俩了。。。)

https://www.jianshu.com/p/fb1177cac1ec
https://blog.csdn.net/sinat_30162391/article/details/52765414

提示一下:完整的swift代码官方demo里面有,可以在那工程里搜相关的关键代码应该就能找到了,就是MAMapKit_2D_Demo这个文件夹里面InsideTestViewController.swift是填充区域的主要就是搜画轮廓线的polyline和多边形的polygon这俩参数(变量)。
其他关于怎么配置高德地图api啥的就不在这里讲了。
下面给出我的全部代码,注释都比较详细,还有包括点击填充区域内外屏幕给出的toast效果。有部分的标注掉的是用来只画轮廓线的:
注意的是,我用的是朝阳区的,但是搜索出来除了北京还有吉林也有一个朝阳。。。。所以在pointLinesArr变量这里做了说明,北京的朝阳有两个多边形构成,所以这样实际上前面的response.districts这里面应该是有两个行政区域(两个朝阳区),这里我走了不少弯路。高德给出的行政划分先是北京朝阳的再是吉林朝阳,所以我在循环让他执行完北京的后就break了。

//
//  pollution_sourceController.swift
//  污染源地图界面
//
//  Created by zhy on 2020/1/19.
//  Copyright © 2020年 zhy. All rights reserved.
//
import UIKit
import MapKit
import CoreLocation
import Toast
class pollution_sourceController: UIViewController, MAMapViewDelegate, AMapSearchDelegate {
    var search: AMapSearchAPI!
    var mapView: MAMapView!
    var currentLocation:CLLocation?//定位
    var polygon:MAPolygon!
    //var polygon_struct: UnsafeMutablePointer<CLLocationCoordinate2D>
    //var polygonview:MAPolygonView
    var overlays: Array<MAOverlay>!
    var select_longtitude : String = ""
    var select_latitude : String = ""
    override func viewDidLoad() {
        super.viewDidLoad()
        AMapServices.shared().enableHTTPS = true
        mapView = MAMapView(frame: self.view.bounds)
        mapView.delegate = self
        mapView.isShowsUserLocation = true
        mapView.userTrackingMode = .followWithHeading// 设置跟随定位模式,将定位点设置成地图中心点
        self.view.addSubview(mapView)
        let r = MAUserLocationRepresentation()//初始化 MAUserLocationRepresentation 对象
        r.showsHeadingIndicator = true
        mapView.showsCompass = true
        mapView.showsScale = true
        mapView.update(r)
        mapView.distanceFilter = 1000
        mapView.zoomLevel = 14
        initSearch()
        overlays = Array()//地图覆盖物数组初始化
        // 发起一次请求
        searchDistrict(withKeyword: "朝阳区")
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }
    func initSearch() {
        search = AMapSearchAPI()
        search.delegate = self
    }
    //MARK: - Action
    func searchDistrict(withKeyword keyword: String?) {
        if keyword == nil || keyword! == "" {
            return
        }
        let request = AMapDistrictSearchRequest()
        request.keywords = keyword
        // 显示商圈,而不是街道
        request.requireExtension = true
        search.aMapDistrictSearch(request)
    }
    func addAnnotation(_ coordinate: CLLocationCoordinate2D, title: String, subTitle: String) -> TGAnnotation {
        let annotation: TGAnnotation = TGAnnotation()
        annotation.coordinate = coordinate
        annotation.title = title
        annotation.subtitle = subTitle
        mapView.addAnnotation(annotation as? MAAnnotation)
        return annotation
    }
    //MARK: - MAMapViewDelegate
    func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
        if annotation.isKind(of: MAPointAnnotation.self) {
            let pointReuseIndetifier = "pointReuseIndetifier"
            var annotationView: MAPinAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier) as! MAPinAnnotationView?
            if annotationView == nil {
                annotationView = MAPinAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier)
            }
            annotationView!.canShowCallout = true
            annotationView!.isDraggable = false
            annotationView!.rightCalloutAccessoryView = UIButton(type: UIButtonType.detailDisclosure)
            return annotationView!
        }
        return nil
    }
    //只画轮廓
    /*func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
        if overlay.isKind(of: MAPolyline.self) {
            let renderer: MAPolylineRenderer = MAPolylineRenderer(overlay: overlay)
            renderer.lineWidth = 8.0
            renderer.strokeColor = UIColor.cyan//青色
            return renderer
        }
        return nil
    }*/
    //填充行政区域
    func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
        if overlay.isKind(of: SelectableOverlay.self) {
            let selectableOverlay: SelectableOverlay = overlay as! SelectableOverlay;
            let actualOverlay: MAOverlay! = selectableOverlay.overlay
            if actualOverlay.isKind(of: MAPolygon.self) {
                let renderer: MAPolygonRenderer = MAPolygonRenderer(overlay: actualOverlay)
                renderer.strokeColor = UIColor.cyan//轮廓颜色
                renderer.lineWidth = 6.0//轮廓粗细
                renderer.fillColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 0.3)
                return renderer
            }
        }
        return nil;
    }
    //点击地图操作(判断是否在填充区域内)
    func mapView(_ mapView: MAMapView!, didSingleTappedAt coordinate: CLLocationCoordinate2D) {
        print("centerCoordinate:\(self.mapView.centerCoordinate.latitude)")
        var judge = false
        for (index, overlay) in mapView.overlays.enumerated().reversed() {
            if (overlay as AnyObject).isKind(of: SelectableOverlay.self) {
                let selectableOverlay: SelectableOverlay = overlay as! SelectableOverlay
                let mapPoint = MAMapPointForCoordinate(coordinate)
                //print("mapPoint:\(mapPoint)")
                let distance = self.mapPointsPerPointInViewAtCurrentZoomLevel()
                // 判断是否选中了overlay
                if isOverlayWithLineWidthContainsPoint(selectableOverlay.overlay, distance, mapPoint){
                    judge = true
                }
            }
        }
        if judge{//选中了填充区域
            self.view.makeToast(String.init(format: "coordinate =  {%f, %f}", coordinate.latitude,coordinate.longitude))
        }else{//没选中填充区域
            self.view.makeToast("您无权限访问")
        }
    }
    //MARK: - Utility
    func mapPointsPerPointInViewAtCurrentZoomLevel() -> Double {
        return Double(self.mapView.metersPerPointForCurrentZoomLevel) * MAMapPointsPerMeterAtLatitude(self.mapView.centerCoordinate.latitude)
    }
    //MARK: - AMapSearchDelegate
    func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {
        print("Error:\(String(describing: error))")
    }
    func onDistrictSearchDone(_ request: AMapDistrictSearchRequest!, response: AMapDistrictSearchResponse!) {
        mapView.removeAnnotations(mapView.annotations)
        mapView.removeOverlays(mapView.overlays)
        if response.count == 0 {
            print(print("规划失败,区域规划结果不存在!"))
            return
        }
        for aDistrict in response.districts {//aDistrict:在搜索到的每个行政区域循环
            var subAnnotations = Array<MAPointAnnotation>()//标注点
            for subDistrict in aDistrict.districts {//返回该行政区划下级的区划对象
                let coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(subDistrict.center.latitude), longitude: CLLocationDegrees(subDistrict.center.longitude))
                let anno = MAPointAnnotation()
                anno.coordinate = coordinate//经纬度
                anno.title = subDistrict.name
                subAnnotations.append(anno)//边界点
                //print("coordinate:\(coordinate)")
            }
            print("aDistrict:\(aDistrict)")
            var pointLinesArr = [String]()//所有属于该区域的经纬度坐标集合(数组中每个""代表一个小区域),如朝阳区有2个
            //mapView.addAnnotations(subAnnotations)
            if aDistrict.polylines != nil {//所有坐标集合
                //var polylines = Array<MAPolyline>()//将坐标整合后的区域(0x开头)
                for polylineString in aDistrict.polylines {//从每个小区域的经纬度坐标字符串数组遍历
                    var polygon_array = coordinatesForString(polylineString,separatorIn: ",", separatorOut: ";")//将字符串中“;”转换为”,“后的小区域数组
                    //let polyline = CommonUtility.polyline(forCoordinateString: polylineString)
                    //polylines.append(polyline!)
                    polygon = MAPolygon(coordinates:&polygon_array, count: UInt(polygon_array.count))//将每个小区域进行填充,构造多边形
                    //print("polygon_array:\(polygon_array)")
                    let selectablePolygon: SelectableOverlay = SelectableOverlay(overlay: polygon)
                    pointLinesArr.append(polylineString)
                    overlays.append(selectablePolygon)
                    mapView.add(polygon)
                }
                print("pointLinesArr.count:\(pointLinesArr.count)")//小区域个数
                //print(pointLinesArr)
                //mapView.addOverlays(polylines)
                mapView.addOverlays(overlays)
            }
            break
        }
        if mapView.overlays.count > 0 {
            mapView.showOverlays(mapView.overlays, animated: true)//立马展示所画区域
            print("mapView.overlays:\(String(describing: mapView.overlays))")
        }
        else {
            mapView.showAnnotations(mapView.annotations, edgePadding: UIEdgeInsetsMake(100, 40, 40, 40), animated: true)
            print("else")
        }
    }
    /// - Parameters:
    ///   - pathStr: 经纬度字符串(示例:114.036217,22.524128;114.036079,22.52401;114.036011,22.523979)
    ///   - separatorIn: 一组经纬度 经度和纬度 之间的分隔符
    ///   - separatorOut: 每 两组经纬度 之间的间隔符
    /// - Returns: [CLLocationCoordinate2D]
    func coordinatesForString(_ pathStr: String?, separatorIn: Character = ",", separatorOut: Character = ";") -> [CLLocationCoordinate2D] {
        guard let pathStr = pathStr else { return [] }
        let coorStrs = pathStr.split(separator: separatorOut)
        var results = [CLLocationCoordinate2D]()
        for coorStr in coorStrs {
            let coordinate = coorStr.split(separator: separatorIn)
            guard coordinate.count == 2, let lng = Double(coordinate[0]), let lat = Double(coordinate[1]) else { continue }
            let point = CLLocationCoordinate2D(latitude: lat, longitude: lng)
            results.append(point)
        }
        return results
    }
    // 点击定位小蓝点进行逆地理编码查询
    func reverseGeocoding(){
        let coordinate = currentLocation?.coordinate
        // 构造 AMapReGeocodeSearchRequest 对象,配置查询参数(中心点坐标)
        let regeo: AMapReGeocodeSearchRequest = AMapReGeocodeSearchRequest()
        regeo.location = AMapGeoPoint.location(withLatitude: CGFloat(coordinate!.latitude), longitude: CGFloat(coordinate!.longitude))
        // 进行逆地理编码查询
            self.search!.aMapReGoecodeSearch(regeo)
    }
    // 定位回调
    func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!, updatingLocation: Bool) {
        if updatingLocation {
            currentLocation = userLocation.location
        let coordinate = currentLocation?.coordinate
        let circle_radius :MACircle = MACircle(center:CLLocationCoordinate2D(latitude: coordinate!.latitude, longitude: coordinate!.longitude), radius: 500)
        mapView.add(circle_radius)
        }
    }
    // 点击Annoation回调
    func mapView(_ mapView: MAMapView!, didSelect view: MAAnnotationView!) {
    // 若点击的是定位标注,则执行逆地理编码
            if view.annotation.isKind(of: MAUserLocation.self){
            reverseGeocoding()
        }
    }
    // 逆地理编码回调
    func onReGeocodeSearchDone(_ request: AMapReGeocodeSearchRequest!, response: AMapReGeocodeSearchResponse!) {
        if (response.regeocode != nil) {
            var title = response.regeocode.addressComponent.city
            title = response.regeocode.addressComponent.province
            //给定位标注的title和subtitle赋值,在气泡中显示定位点的地址信息
            mapView?.userLocation.title = title
            mapView?.userLocation.subtitle = response.regeocode.formattedAddress
        }
    }
    deinit {
        print("释放")
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值