地圖和定位功能的實現-篇幅略大,手機慎入


來一起學習下地圖和定位的使用吧,如有不足,歡迎指正
 
一.定位功能
1.ios7中的定位
 
     1.1 導入 CoreLocation框架
 
     1.2 創建 CLLocationManager對象
          注意:要用強指針指向這個對象,一般采用懶加載來創建     
1 private lazy var mgr : CLLocationManager = CLLocationManager()
 
     1.3 設置代理,實現代理方法
 
     1.4 開始定位
mgr.startUpdatingLocation()
    
     1.5 優點:不需要設置用戶的授權
          在info.plist加上一個key   Privacy - Location Usage Description 寫在value上的文字,可以顯示在提示權限的文本框內
 
2.ios8(之后)的定位
 
     2.1 請求定位步驟
          2.11 導入CoreLocation框架
          2.12 懶加載CLLocationManager對象
          2.13 請求授權 (1) whenInUse (2) always
          2.14 注意:必須把授權對應的key值 添加到info.plist文件中
          2.15 設置代理,實現代理方法
          2.16 開始定位
 
     2.2 定位屬性的應用
          2.21 精確度的使用
               desiredAccuracy精確度越高,越耗電
               屬性接收double類型的值,不過最好傳系統給定好的值
         kCLLocationAccuracyBestForNavigation: 導航精確度(最精確)
         kCLLocationAccuracyBest: 最好精確度(默認)
         kCLLocationAccuracyNearestTenMeters: 10米的誤差
         kCLLocationAccuracyHundredMeters: 100米的誤差
         kCLLocationAccuracyKilometer: 千米誤差
         kCLLocationAccuracyThreeKilometers: 三千米的誤差 
mgr.desiredAccuracy = kCLLocationAccuracyBestForNavigation
 
          2.22 移動一段距離,再次重新定位
           設置用於移動多少距離,重新進行定位         
mgr.distanceFilter = 100
 
     2.3 位置信息的獲取
          2.31 發送完請求定位,怎么獲取位置信息?
               在代理方法的閉包中,有一個數組,返回了很多信息在里面
     
          2.32 我們常用的信息就是經緯度
 
 
二.計算兩個經緯度的距離
 
1.獲取當前位置信息
     1.1 導入框架
     1.2 懶加載管理者對象
     1.3 請求授權
     1.4 添加key值
     1.5 設置代理,實現代理方法
     1.6 開始定位     
 
2.獲取另一個位置的經緯度
 
3.計算兩個位置的距離   distanceFromLocation
 
 
三.簡易指南針的制作
 
1.實現思路
     監聽手機頭方向的改變,在手機屏幕上放一張圖片,始終指向北(根據手機方向的改變旋轉)
 
2.界面搭建
     拖一個UIImageView放在屏幕中央,里面放一張圖片
 
3.監聽手機頭方向的改變
     3.1 怎么監聽?
          通過發送請求(定位服務),獲取手機頭的方向進行監聽
 
     3.2 具體實現 
          3.21 導入CoreLocation框架
          3.22 懶加載CLLocationManager對象
          3.23 請求授權 (1) whenInUse (2) always
          3.24 注意:必須把授權對應的key值 添加到info.plist文件中
          3.25 設置代理,實現代理方法
          3.26 請求手機頭方向
          3.27 獲取真北方向
          3.28 將真北方向轉換為弧度
          3.29 讓圖片根據弧度進行旋轉(注意:圖片旋轉的弧度要取反 ,  要和屏幕旋轉方向相反才能保持一直指向一個方向)
 
 
4.對指南針優化
     4.1 真實的指南針指向一個位置,會來回擺動兩下才固定位置
          代碼實現的指南針沒有這個效果
     
     4.2 如何實現這個效果?
          可以通過一個動畫來實現 
    // Damping : 阻力系數 (0~1.0)      initialSpringVelocity:回彈速度
        UIView.animateWithDuration(0.5, delay: 0.0, usingSpringWithDamping: 0.8, initialSpringVelocity: 5.0, options: [], animations: {
            self.imageView.transform = transform
            }, completion: nil)
 
四.區域監聽
 
1.需求,當進入某指向區域,提醒用戶進入該區域,離開該區域也對用戶進行提醒
 
2.實現方案步驟
     2.1 懶加載 CLLocationManager對象
     2.2 請求授權(注意:必須使用alyays授權方式) ,配置info文件
     2.3 設置代理
     2.4 創建監聽區域
     2.5 實現代理方法 並 開始監聽
 
 
3.注意點
     3.1 當之前添加過監聽區域時,再次添加新的監聽區域,還會對之前的區域進行監聽
     3.2 不想監聽之前的區域,必須通過代碼移除之前的區域
 
五.地理編碼&反地理編碼
 
需求:輸入地理名稱,地理編碼獲得該位置的經緯度.   輸入經緯度,輸出對應位置的地理名稱
 
1.界面搭建
    1.1  整個界面放在屏幕的中心,怎么實現?
          1.11 可以用view包裝 
               優缺點:要做大量的約束  , 但可以應用於任何版本
 
          1.12 ios9之后可以用UIStackView來包裝
               優缺點:布局簡便   只能適用於ios9(之后)
 
     
2.地理編碼
     2.1 拿到用戶輸入的地理名稱 (導入框架CoreLocation)
     2.2 地理編碼
          2.21 創建 CLGeocoder對象
 
          2.22 對地理名稱進行地理編碼
     geocoder.geocodeAddressString(address) { (<#[CLPlacemark]?#>, <#NSError?#>) in
            <#code#>
        }
 
          2.23 對閉包中的CLPlacemark數據就行解析(遍歷)
               一個地理名稱可能對應多個地方,所以編碼后的到的結果是一個數組
     
          2.24 獲取數組中元素的地理位置(經緯度)
 
          2.25 將經緯度顯示到界面
 
3.反地理編碼
     3.1 拿到用戶輸入的經緯度
     3.2 對經緯度進行反地理編碼
          3.21 創建 CLGeocoder對象
          
          3.22 對經緯度進行反地理編碼
     geocoder.reverseGeocodeLocation(location) { (<#[CLPlacemark]?#>, <#NSError?#>) in
            <#code#>
        }
 
          3.23 對閉包中的CLPlacemark數據就行解析(遍歷)
               一個經緯度可能對應多個位置(蘋果這么設計的)  所以編碼后返回一個數組
               一個位置包含多個信息(省/市/街道/國家/經緯度/)  編碼后的結果是字典數組
 
          3.24 取出數組中的一個位置(字典),再獲取位置信息(取出字典的元素)
               
          3.25 把獲取到的地理名稱顯示到界面
 
地理編碼&反地理編碼源代碼
 1 class ViewController: UIViewController {
 2    
 3     // MARK:- 控件屬性
 4     @IBOutlet weak var addressTextView: UITextView!
 5     @IBOutlet weak var latitudeTextField: UITextField!
 6     @IBOutlet weak var longitudeTextField: UITextField!
 7     // MARK:- 懶加載屬性
 8     private lazy var geocoder : CLGeocoder = CLGeocoder()
 9 }
10 
11 // MARK:- 地理編碼
12 extension ViewController {
13     @IBAction func geocode() {
14        
15         // 1.獲取用戶輸入的地址名稱
16         guard let address = addressTextView.text else {
17             return
18         }
19         // 2.對地理名稱進行地理編碼
20         geocoder.geocodeAddressString(address) { (placemarks : [CLPlacemark]?, error : NSError?) in
21             // 1.錯誤校驗
22             if error != nil {
23                 print(error)
24                 return
25             }
26             // 2.對結果進行校驗
27             guard let placemarks = placemarks else {
28                 return
29             }
30             // 3.遍歷所有的結果
31             for place in placemarks {
32                 print(place.name)
33                
34                 // 獲取地理位置
35                 guard let location = place.location else {
36                     continue
37                 }
38                
39                 // 獲取經緯度
40                 let latitude = location.coordinate.latitude
41                 let longitude = location.coordinate.longitude
42                
43                 // 將經緯度顯示textField中
44                 self.latitudeTextField.text = "\(latitude)"
45                 self.longitudeTextField.text = "\(longitude)"
46             }
47         }
48     }
49 }
50 
51 
52 // MARK:- 反地理編碼
53 extension ViewController {
54     @IBAction func reverseGeocode() {
55         // 1.獲取用戶輸入的經緯度
56         guard let latitude = latitudeTextField.text, let longitude = longitudeTextField.text else {
57             return
58         }
59        
60         // 2.將經緯度轉成CLLocation對象
61         guard let latitudeD = Double(latitude), let longitudeD = Double(longitude) else {
62             return
63         }
64         let location = CLLocation(latitude: latitudeD, longitude: longitudeD)
65        
66         // 3.反地理編碼
67         geocoder.reverseGeocodeLocation(location) { (placemarks : [CLPlacemark]?, error : NSError?) in
68             // 1.錯誤校驗
69             if error != nil {
70                 print(error)
71                 return
72             }
73            
74             // 2.對結果進行校驗
75             guard let placemarks = placemarks else {
76                 return
77             }
78             // 3.遍歷結果
79             for place in placemarks {
80                 guard let addressDict = place.addressDictionary else {
81                     continue
82                 }
83                
84                 guard let addressArray = addressDict["FormattedAddressLines"] as? [String] else {
85                     continue
86                 }
87                
88                 guard let address = addressArray.last else {
89                     continue
90                 }
91                
92                 self.addressTextView.text = address
93             }
94         }
95     }
96 }
 
六.把定位封裝為工具類
 
1.將工具類設計成單例對象
 
2.封裝請求方法,在方法中傳入閉包
     2.1 使用屬性將閉包保存起來. (因為在代理方法才能拿到位置信息)
     2.2 請求用戶位置(1.懶加載管理者對象,並在對象中直接設置請求授權和代理)
 
3.在代理方法中獲得用戶位置信息,並賦值給閉包屬性
 
4.停止請求用戶的位置
     mgr.stopUpdatingLocation()
 
5.當第一次發送請求位置信息,會返回多次位置信息,怎么解決這個問題?
     用戶只需要定義一個Bool屬性,對屬性進行判斷,為true就接收返回的位置信息
 
七.使用第三方框架請求位置信息
 
去github搜索LocationManager 找到框架去使用
一般用oc版的,swift也能用
 
 
*********************地圖篇*************************
 
一.地圖的基本展示
 
1.地圖可以用一個MapView控件來展示
     注意:要導入MKMapKit框架
 
2.地圖的展示類型,可以通過屬性 mapType設置
     地圖分為:標准地圖,衛星地圖,混合地圖   ios9之后新出了: 三維混合/三維衛星地圖
 
3.地圖上可以展示哪些的內容
     比例尺,指南針,交通狀況,標志建築,顯示用戶位置(后面詳細介紹)
 
4.可以對地圖進行哪些操作
     縮放:zoomEnabled
     旋轉:rotateEnabled
     滾動:scrollEnabled
     
 
二.顯示用戶的位置
 
1.怎么顯示用戶的位置?
     1.1 設置地圖的一個屬性即可mapView.showsUserLocation = true  或 mapView.userTrackingMode = .FollowWithHeading/. Follow
     1.2 注意:一定要設置請求授權
          1.21 創建 CLLocationManager對象
          1.22 調用方法授權  requestWhenInUseAuthorization 或 always
          1.23 在info文件中添加對應的key值
          
2.獲取用戶的位置
     2.1 設置地圖的代理
     2.2 實現代理方法
          在代理方法中通過userLocation.location?.coordinate 拿到經緯度
 
3.跟蹤用戶的位置
     3.1 首先要獲取用戶的位置
     3.2 設置屬性即可  
mapView.userTrackingMode = .FollowWithHeading/. Follow
 
4.設置地圖的顯示區域
     4.1 通過一個屬性就可以設置(一般在代理方法中設置)
mapView.setRegion(<#T##region: MKCoordinateRegion##MKCoordinateRegion#>, animated: <#T##Bool#>)
     
     4.2 需要傳入MKCoordinateRegion參數,那么就需要創建這個參數    
MKCoordinateRegion(center: <#T##CLLocationCoordinate2D#>, span: <#T##MKCoordinateSpan#>)
    
     4.3 創建MKCoordinateRegion又需要傳入CLLocationCoordinate2D和MKCoordinateSpan參數
 
     4.4 創建CLLocationCoordinate2D參數(經緯度)  可以在代理方法中獲得
 
     4.5 創建MKCoordinateSpan參數   1緯度 = 111km     
 let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
          

 

5.點擊按鈕,回到用戶的位置
     5.1 當用戶拖動地圖時,想讓地圖回到自己的位置,如果還需要拖動回來就太麻煩了
          可以設置一個按鈕:點擊按鈕,立刻讓地圖的中心點就是自己的位置
 
     5.2 怎么實現?
          獲取用戶的位置(經緯度coordinate) ,將這個位置設置為地圖的中心點即可
 
 
三.在地圖上展示大頭針
 
1.添加大頭針
     1.1 創建大頭針對象 addAnnotation(annotation: MKAnnotation)
          1.11 需要創建一個MKAnnotation
          1.12 進去頭文件,發現MKAnnotation 是一個協議, 也就是需要傳一個遵守該協議的對象
          1.13 自定義一個模型,遵守協議 , 協議里面只有三個計算屬性
               也就是說,只需要實現這三個屬性(在模型中定義這三個屬性  注意:要定義為普通屬性)
          1.14 創建模型對象
 
     1.2 將大頭針對象添加到mapView中
     addAnnotation(annotation: MKAnnotation)
     
 
2.點擊屏幕,在點擊位置添加大頭針
     2.1 獲取用戶點擊的位置
     2.2 將點擊的點轉成經緯度
     2.3 根據經緯度創建大頭針模型
     2.4 將大頭針模型添加到mapView中
     
     
3.自定義大頭針(修改大頭針的子類)
     3.1 系統給定的大頭針樣式單一,我們想要其它樣式的大頭針,需要自定義大頭針
 
     3.2 怎么自定義大頭針?
          大頭針能添加到view上,一定是一個控件,只要拿到這個控件,就可以進行修改
 
     3.3 怎么拿到大頭針的view?
          在代理方法中會把大頭針添加到mapView上,這個時候就可以拿到
 
     3.4 修改完大頭針,發現點擊大頭針看不到title和subTitle了  為什么?
          需要設置一個屬性才可以看到annoView?.canShowCallout = true
 
     3.5 設置大頭針的樣式,發現標記用戶位置的圖標也變為了大頭針,  不想讓標記位置的圖標變為大頭針,怎么辦?
          判斷大頭針是否為用戶值得大頭針 MKUserLocation是的話就返回nil  (返回nil就是系統默認的大頭針樣式)
 
     3.6 對大頭針進行性能優化(重用)
          和設置tableView的重用步驟差不多
   
 
4.自定義大頭針(修改大頭針,自定義大頭針的image)
     
     4.1 系統自帶的大頭針只能顯示一個大頭針,我們想讓大頭針顯示圖片,只能自定義
          新建一個類,繼承自 MKAnnotationView  用的時候,直接創建這個類即可
     
     4.2 怎么設置大頭針顯示的圖片?
          只需要設置Image屬性即可
 
     4.3 如何讓大頭針顯示不同的圖片?
           對大頭針類型進行判斷 ,給不同類型大頭針設置不同的圖片即可
 
      4.4 大頭針非常多,判斷的話很麻煩,也沒技術含量,怎么解決?
           給大頭針對象添加一個屬性: iconName 屬性里面保存對應的照片名稱即可
           設置的時候,只需要取出屬性的值,設置給UIImageView即可
     
     4.5 想在title左右兩邊也顯示圖片,怎么辦?
           設置兩個屬性即可 leftCalloutAccessoryView     rightCalloutAccessoryView     
 
 
5.代碼重構
     5.1 為什么要進行代碼重構?
          把自定義大頭針的操作全部寫在控制器中,控制器太臃腫
     
     5.2 怎么對控制器進行”瘦身"
          把自定義大頭針的代碼抽取到一個view中
 
     5.3 怎么抽取?
          自定義大頭針的view ,把相關代碼封裝到view里面
 
     5.4 抽取代碼要用到模型和mapView怎么辦?
          在自定義view中定義模型屬性   把mapView當成參數傳進去
 
     5.5 注意: 父類中已經存在這個模型屬性了,在子類中不允許重復定義,怎么辦?
          重復定義屬性的時候,重寫屬性監聽器方法即可
      
6.給大頭針添加動畫
     6.1 系統自帶的大頭針可以設置墜落動畫,自定義的大頭針怎么設置動畫?
          我們只要拿到大頭針view的frame就能實現墜落動畫
 
     6.2 怎么拿到大頭針的frame
          只需要獲取大頭針的view即可
 
     6.3 在代理方法中可以拿到view
 
     6.4 執行動畫步驟
          6.41 保存大頭針的y值
          6.42 設置大頭針的y值為0
          6.43 再設置大頭針的y值為原來的值,並執行動畫
 
 
四.實現導航功能(了解)
 
1.利用系統的地圖實現導航
     1.1 在自己app中打開系統地圖,實現導航   
openMapsWithItems(mapItems: [MKMapItem], launchOptions: [String : AnyObject]?) -> Bool
     
     1.2 需要在方法中傳入一個數組[MKMapItem](起點,終點) 和一個字典 [String : AnyObject] (導航的參數:駕車還是步行等)
     
     1.3 創建MKMapItem類型的起點和終點
 
     1.4 起點通過的一個方法就能實現,終點要利用地理編碼獲得
 1           @IBAction func startNavigating() {
 2         // 1.獲取用戶輸入的地址
 3         guard let address = destinationTextField.text else {
 4             return
 5         }
 6         // 2.地理編碼
 7         geocoder.geocodeAddressString(address) { (placemarks : [CLPlacemark]?, error : NSError?) in
 8             // 3.對錯誤進行校驗
 9             if error != nil {
10                 return
11             }
12             // 4.獲取placemark
13             guard let clpm = placemarks?.first else {
14                 return
15             }
16             // 5.創建終點的item
17             let mkpl = MKPlacemark(placemark: clpm)
18             let destinationItem = MKMapItem(placemark: mkpl)
19            
20             // 6.獲取起點的item
21             let sourceItem = MKMapItem.mapItemForCurrentLocation()
22            
23             // 7.調用對應的導航方法
24             self.startNavigationWithSoureItem(sourceItem, destionationItem: destinationItem)
25         }
26     }
27    
28     private func startNavigationWithSoureItem(soureItem : MKMapItem, destionationItem : MKMapItem) {
29         // 1.獲取起點和終點的item,並且放入到數組中
30         let items = [soureItem, destionationItem]
31         // 2.設置導航的參數
32         /*
33          MKLaunchOptionsDirectionsModeKey: 步行/駕車
34          MKLaunchOptionsMapTypeKey: 地圖類型
35          MKLaunchOptionsShowsTrafficKey: 是否顯示交通狀況
36         */
37         var launchOptions = [String : NSObject]()
38         launchOptions[MKLaunchOptionsDirectionsModeKey] = MKLaunchOptionsDirectionsModeDriving
39         launchOptions[MKLaunchOptionsMapTypeKey] = MKMapType.Hybrid.rawValue
40         launchOptions[MKLaunchOptionsShowsTrafficKey] = true
41        
42         // 3.開始導航
43         MKMapItem.openMapsWithItems(items, launchOptions: launchOptions)
44     }
45 }
 
2.請求整個導航線路,在自己app中把線路畫出來
     2.1 可以通過 MKDirections對象的一個方法實現
 
     2.2 首先要創建 MKDirections對象
 MKDirections(request: <#T##MKDirectionsRequest#>)
 
     2.3 還需要創建MKDirectionsRequest對象
 
     2.4 創建MKDirectionsRequest對象,並設置屬性(起點位置和終點位置)
 
     2.5 通過MKDirections對象方法請求 calculateDirectionsWithCompletionHandler路線
 
     2.6 獲取所有路線,並把路線通過 addOverlay方法添加到mapView上

 

五.集成百度地圖
 
1.如何使用第三方SDK
     1.1 搜索想要集成的SDK
     1.2 進入官方下載SDK開發包
     1.3 查看demo程序(運行看看有哪些功能) 
     1.4 根據API一步步集成(官方一般有文檔教程)
 
2.基本集成
     2.1 先將需要集成的功能的框架導入到項目
     2.2 創建橋接文件(根據需求創建, 只有開發包是oc  自己代碼是swift才需要創建)
     2.3 在橋接文件中導入頭文件(官方文檔一般會給需要導入的頭文件)
     2.4 配置橋接文件
     
3.請求授權
   3.1 如何授權?
          在AppDelegate文件中進行授權
 
     3.2 授權完,運行直接報錯,為什么?
          百度一些框架依賴系統的一些框架,還需要導入系統的一些框架
 
4. BMKMapView的展示
     4.1 創建 BMKMapView對象
     4.2 設置frame,添加到屏幕上
 
5.定位功能的實現
     通過代理就可以實現
 
6.POI檢索功能(查找功能)
     注意:發起檢索一定要在地圖添加到view上之后
 
   
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM