iOS 定位服務與地圖

CoreLocation(定位與地理編碼等)

使用步驟:

  1. 導入CoreLocation庫
  2. 創建CLLocationManager對象
  3. 請求用戶授權 --- 需要在Info.plist中加入 NSLocationWhenInUseUsageDescription 這個鍵
  4. 設置代理 --- 並實現相應代理方法
  5. 調用開始定位方法
  6. 調用結束定位方法

    import UIKit
    import CoreLocation
    
    class ViewController: UIViewController {
        
        // 1. 創建CLLocationManager對象
        lazy var locationManger = CLLocationManager()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 2. 請求用戶授權
            locationManger.requestWhenInUseAuthorization()
            // 3. 設置代理
            locationManger.delegate = self
            // 4. 調用開始定位方法
            locationManger.startUpdatingLocation()
            
        }
    }
    
    // MARK: - 實現相應代理方法
    extension ViewController: CLLocationManagerDelegate {
        func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            let lastLocation = locations.last!
            print(lastLocation)
            
            // 5. 調用結束定位方法
            manager.stopUpdatingLocation()
        }
    }

持續定位優化(設置這些屬性可降低功耗)

  • 設置距離篩選

    // 距離篩選器,當位置發生至少10米的改變時纔會調用更新位置的代理方法
    locationManger.distanceFilter = 10
  • 設置定位精確度

    // 定位的精準度
    /*
    * kCLLocationAccuracyBestForNavigation 精準度儘可能高(導航時使用)
    * kCLLocationAccuracyBest              精準度儘可能高
    * kCLLocationAccuracyNearestTenMeters  10米以內誤差
    * kCLLocationAccuracyHundredMeters     百米誤差
    * kCLLocationAccuracyKilometer         千米誤差
    * kCLLocationAccuracyThreeKilometers   三千米誤差
    */
    locationManger.desiredAccuracy = kCLLocationAccuracyBest

CLLocation常用屬性與方法

  • 經緯度

    let location = lastLocation
    let coordinate = location.coordinate
    // 維度
    print(coordinate.latitude)
    // 經度
    print(coordinate.longitude)
  • 兩個位置之間的距離(直線距離)

    let distance = location.distance(from: location2)

關於授權

  • 使用期間授權:只有應用在前臺(屏幕顯示應用程序主界面)時,應用纔開使用定位服務

    // 對應Info.plist中的 NSLocationWhenInUseUsageDescription,描述爲何使用定位服務
    locationManger.requestWhenInUseAuthorization()
  • 始終授權:即使應用在後臺,應用也可以使用定位服務

    // 對應Info.plist中的 NSLocationAlwaysAndWhenInUseUsageDescription
    locationManger.requestAlwaysAuthorization()

CLGeocoder(地理編碼)

  • 地理編碼(使用地名獲取地理信息)

    CLGeocoder().geocodeAddressString("上海市") { (placemarks, error) in
        // 使用前需要判斷下placemarks, error
        // 需要注意重名問題
        print(placemarks)
    }
  • 反地理編碼(使用經緯度獲取位置信息)

    CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: 31.23727100, longitude: 121.45111100)) { (placemarks, error) in
        // 使用前需要判斷下placemarks, error
        print(placemarks)
    }
  • 注意:placemarks是[CLPlacemark]類型,可以通過其屬性獲取詳細地址,街道地址,城市名等位置信息

MapKit

MapView

  • 使用:

    • 導入MapKit框架 import MapKit
    • 對於storyboard或xib從控件庫中拖拽一個map kit view到一個view上;或者使用代碼創建一個MKMapView對象添加到視圖當中
  • 在地圖上顯示當前所在位置

    • 獲取授權並設置 userTrackingMode 屬性

      var locationManager = CLLocationManager()
      locationManager.requestWhenInUseAuthorization()
      
      // 要使用代理方法就設置,否則不用設置
      mapView.delegate = self
      
      // case none = 0 // the user's location is not followed
      // case follow = 1 // the map follows the user's location 顯示位置
      // case followWithHeading = 2 // the map follows the user's location and heading 顯示位置和方向
      mapView.userTrackingMode = .follow
    • 使用代理可獲取最新位置的詳細信息

      extension MapController: MKMapViewDelegate {
          func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
              print(userLocation.location)
              
              // 可在此設置用戶所在位置大頭針的信息
              //CLGeocoder().reverseGeocodeLocation(userLocation.location!) { (placemarks, error) in
                  //    let placemark = placemarks?.last
                  // 被點擊後彈出氣泡的標題與子標題
                  //    userLocation.title = placemark?.locality
                  //    userLocation.subtitle = placemark?.name
              //}
          }
      }
  • 設置地圖類型

    // A street map that shows the position of all roads and some road names.
    // case standard = 0  // 標準地圖,有街道信息等
    
    // Satellite imagery of the area.
    // case satellite = 1 // 衛星圖
    
    // A satellite image of the area with road and road name information layered on top.
    // case hybrid = 2 // 衛星圖並顯示街道信息
    
    /* 這幾種暫時在中國區沒啥用
    // @available(iOS 9.0, *)
    // case satelliteFlyover = 3
    
    // @available(iOS 9.0, *)
    // case hybridFlyover = 4
    
    // @available(iOS 11.0, *)
    // case mutedStandard = 5
    */
    mapView.mapType = .standard
  • 設置地圖中心點座標或顯示區域

    // 設置地圖所顯示的中心點
    // mapView.centerCoordinate = userLocation.location!.coordinate
    
    // 設置地圖所顯示的中心點和所顯示的區域
    // mapView.region = MKCoordinateRegion(center: userLocation.location!.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
    
    // 設置地圖所顯示的中心點和所顯示的區域(當從另一區域變化到所設置的區域時有動畫)
    // 可調用此屬性進行地圖的放大與縮小
    mapView.setRegion(MKCoordinateRegion(center: userLocation.location!.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)), animated: true)
  • 額外信息或控件的顯示與隱藏

    • 指北針

      // 顯示指北針 默認就是true,當用戶旋轉地圖時顯示,點擊回到初始方向
      mapView.showsCompass = true
    • 交通狀況

      // 顯示交通狀況
      mapView.showsTraffic = true
    • 比例尺

      // 顯示比例尺
      mapView.showsScale = true

大頭針

  • 基本使用
  1. 自定義大頭針數據模型類(需遵守MKAnnotation協議)
  2. 創建大頭針對象
  3. 將大頭針添加到地圖上

    // 1. 自定義大頭針數據模型類
    class MyAnnotation: NSObject, MKAnnotation {
        var coordinate: CLLocationCoordinate2D
    
        var title: String?
    
        var subtitle: String?
        
        init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String?) {
            self.coordinate = coordinate
            self.title = title
            self.subtitle = subtitle
        }
    }
    
    // 寫在存在MapView的視圖控制器的方法中
    // 2. 創建大頭針對象
    let annotiton1 = MyAnnotation(coordinate: CLLocationCoordinate2D(latitude: 39.90680600, longitude: 116.39877350), title: "北京", subtitle: "中國北京")
    // 2. 創建大頭針對象
    let annotiton2 = MyAnnotation(coordinate: CLLocationCoordinate2D(latitude: 31.23170600, longitude: 121.47264400), title: "上海", subtitle: "中國上海")
            
    // 3. 將大頭針添加到地圖上
    mapView.addAnnotations([annotiton1, annotiton2])
  • 自定義大頭針視圖(實現下面的代理方法)

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        // 如果是用戶位置的大頭針視圖直接返回nil,否則會將其也變爲自定義大頭針視圖
        guard !(annotation is MKUserLocation) else {
            return nil
        }
    
        // 1. 從緩存池中獲取可重用的大頭針視圖 需自己實現 MyAnnotationView 的定義
        let view = mapView.dequeueReusableAnnotationView(
                withIdentifier: "MyAnnotationView") as? MyAnnotationView
        annotationView = view ?? MyAnnotationView(annotation: annotation,
                                                          reuseIdentifier: "MyAnnotationView")
        // 2. 設置MyAnnotationView需要設置的屬性
        ……
        // 返回自定義大頭針視圖
        return annotationView
    }

地圖上畫線

  1. 創建起點MKMapItem
  2. 創建終點MKMapItem
  3. 創建方向請求並設置起點終點
  4. 根據請求創建MKDirections對象
  5. 計算路線
  6. 添加路線到地圖視圖上
  7. 實現代理方法
let direction = "上海"

CLGeocoder().geocodeAddressString(direction!) { (placemarks, error) in
    
    // 1. 創建起點MKMapItem
    let sourceItem = MKMapItem.forCurrentLocation()
    // 2. 創建終點MKMapItem
    let destinationItem = MKMapItem(placemark: MKPlacemark(placemark: placemarks!.last!))

    // 3. 創建方向請求並設置起點終點
    let request = MKDirections.Request()
    request.source = sourceItem
    request.destination = destinationItem
    request.transportType = .automobile

    // 4. 根據請求創建MKDirections對象
    let directions = MKDirections(request: request)
    // 5. 計算路線
    directions.calculate { (response, error) in
        guard let response = response else {
            if let error = error {
                print("Error: \(error)")
            }
            return
        }

        response.routes.forEach({ (route) in
            // 6. 添加路線到地圖視圖上
            let polyine = route.polyline
            self.mapView.addOverlay(polyine, level: .aboveRoads)
        })
    }
}

// 7. 實現代理方法
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    
    let renderer = MKPolygonRenderer(overlay: overlay)
    
    // 設置線的顏色
    renderer.strokeColor = .blue
    // 設置線寬
    renderer.lineWidth = 5

    return renderer
}

導航(跳轉到系統地圖)

  1. 使用導航目的地創建一個MKMapItem
  2. 構建打開系統地圖時的選項(如導航模式、地圖類型等)
  3. 調用openMaps方法打開系統地圖
// 0. 導航目的地
let destination = "上海"

CLGeocoder().geocodeAddressString(direction!) { (placemarks, error) in
    // 1. 使用導航目的地創建一個MKMapItem
    let destinationItem = MKMapItem(placemark: MKPlacemark(placemark: placemarks!.last!))
    
    // 2. 構建打開系統地圖時的選項(如導航模式、地圖類型等)
    let options = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
                   MKLaunchOptionsMapTypeKey: 0,
                   MKLaunchOptionsShowsTrafficKey: true] as [String : Any]
    
    // 3. 調用openMaps方法打開系統地圖
    MKMapItem.openMaps(with: [destinationItem], launchOptions: options)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章