詳解iOS集成GoogleMap(定位、搜索)
簡介:
最近花了些時間看了GoogleMap官方文件并集成到國際版app中,網(wǎng)上關(guān)于GoogleMap for iOS的講解相對Android來說少一點,比較有幫助的幾乎全是英文文檔。下面是我開發(fā)過程中遇到的坑、以及采用的解決方法。
集成GoogleMap步驟:
- 1、Cocoapods導(dǎo)入pod 'GoogleMaps'
- 2、獲取API密匙(前提是已經(jīng)在GoogleMapSDK中創(chuàng)建好自己的應(yīng)用)
- 3、配置plist文件搭建定位環(huán)境
- 4、調(diào)用代理方法實現(xiàn)需求
tips:pod 'GoogleMaps'、pod 'GooglePlaces'、pod 'GooglePlacePicker'這三個框架。(GoogleMaps:顯示基本的定位功能;GooglePlaces:實現(xiàn)搜索功能,官方文檔叫做地點自動完成;GooglePlacePicker:是實現(xiàn)獲取某個POI的的詳細(xì)信息,比如名字、詳細(xì)地址、路線等)
景點(POI)包括公園、學(xué)校和政府大樓,等等。 另外,如果地圖類型為 kGMSTypeNormal,商家景點默認(rèn)將顯示在地圖上。 商家景點表示商店、餐館和酒店之類的商家。
按照 Google Places API 中的定義,一個 POI 對應(yīng)于一個地點。 例如,休閑公園為景點,但噴泉之類的地點通常不屬于景點(除非它們具有國家或歷史意義)。
配置plist文件:
打開plist的代碼源文件,輸入:
定位:
一、在AppDelegate 頭文件 導(dǎo)入框架
#import
二、向您的 application:didFinishLaunchingWithOptions: 方法添加以下內(nèi)容,使用我們剛才獲取到的 API 密鑰替代 YOUR_API_KEY:
[GMSServices provideAPIKey:@"YOUR_API_KEY"];
tips:這一步是在啟動app的時候,GoogleMap準(zhǔn)備代理工作。
三、在我們需要顯示地圖的控制器調(diào)用API方法
@property (nonatomic,strong) CLLocationManager *locationManager;//地圖定位對象 @property (nonatomic,strong) GMSMapView *mapView;//地圖 @property (nonatomic,strong) GMSMarker *marker;//大頭針 @property (nonatomic,strong) GMSPlacesClient * placesClient;//可以獲取某個地方的信息 //注冊的代理 @interface TestMapViewController ()
tips:這是在控制器.h文件聲明的屬性。
(一)初始化一個地圖對象
GMSMapView:是控制地圖的外觀類
GMSCameraPosition:是控制地圖要顯示的內(nèi)容類
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-23.12960481 longitude:113.30887721 zoom:Level]; self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; self.mapView.delegate = self; //注冊代理屬性 self.mapView.settings.compassButton = YES;//顯示指南針 [self.view addSubview:self.mapView];
tips:上面的經(jīng)緯度可以隨便傳一個,之后會獲取到新的經(jīng)緯度并更新位置
(二)初始化一個定位管理者對象
if (self.locationManager == nil) { self.locationManager = [[CLLocationManager alloc]init]; } self.locationManager.delegate = self; [self.locationManager requestAlwaysAuthorization];//授權(quán)方式,如果在后臺也需要定位,那就選擇 requestAlwaysAuthorization。 self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;//最精確的定位 self.locationManager.distanceFilter = kCLDistanceFilterNone; // 默認(rèn)是kCLDistanceFilterNone,也可以設(shè)置其他值,表示用戶移動的距離小于該范圍內(nèi)就不會接收到通知 [self.locationManager startUpdatingLocation];
tips:CLLocationManager 是負(fù)責(zé)獲取用戶行為的類,列如獲取用戶當(dāng)前位置信息。更多詳細(xì)信息請閱覽CLLocationManager。里面講解CLLocationManager的一些應(yīng)用場景并有代碼實例。
運行app:這時候我們會看到并沒有實景地圖出來,原因是:前面提到的GMSCameraPosition類,我們并沒有在定位成功之后將定位內(nèi)容賦它。
GMSCameraPosition類,它是負(fù)責(zé)顯示定位內(nèi)容的。很重要!
(三)在定位成功的API代理方法中,獲取經(jīng)緯度并轉(zhuǎn)成影像賦值
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ CLLocation *curLocation = [locations lastObject]; // 通過location 或得到當(dāng)前位置的經(jīng)緯度 CLLocationCoordinate2D curCoordinate2D = curLocation.coordinate; GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:curCoordinate2D.latitude longitude:curCoordinate2D.longitude zoom:Level]; CLLocationCoordinate2D position2D = CLLocationCoordinate2DMake(curLocation.coordinate.latitude, curLocation.coordinate.longitude); self.mapView.camera = camera;//這句話很重要很重要,將我們獲取到的經(jīng)緯度轉(zhuǎn)成影像并賦值給地圖的camera屬性 [self.locationManager stopUpdatingLocation];//定位成功后停止定位 }
tips:locationManager: didUpdateLocations: 代理方法是GoogleMap 中實現(xiàn)定位成功后回調(diào)的代理方法,你可以在這里獲取到經(jīng)緯度。
運行app:這時候地圖就出來了
添加大頭針
GMSMarker類是負(fù)責(zé)顯示大頭針,默認(rèn)是紅色,你可以自定義大頭針,用圖片或者改變顏色,具體看官方文檔GMSMarker。
self.marker = [GMSMarker markerWithPosition:position2D]; self.marker.map = self.mapView;
tips:position2D是在定位成功之后轉(zhuǎn)換得到的CLLocationCoordinate2D屬性經(jīng)緯度值。
小坑提示:這時候有可能會出現(xiàn),定位成功之后出現(xiàn)多個大頭針。原因是:進行定位的時候,map獲取多個預(yù)測位置,從而產(chǎn)生生成多個大頭針的現(xiàn)象。解決辦法:在每次生成大頭針之前先清除之前的那個,只生成最精準(zhǔn)的最后一個。
[self.marker.map clear]; self.marker.map = nil;
反編碼(經(jīng)緯度轉(zhuǎn)成具體位置):
CLGeocoder *geocoder = [[CLGeocoder alloc]init]; //反地理編碼 [geocoder reverseGeocodeLocation:curLocation completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) { if (error) { }else{ CLPlacemark *placemark = [placemarks objectAtIndex:0];//第一個位置是最精確的 //賦值詳細(xì)地址 DLog(@"placemark---路號name:%@-市l(wèi)ocality:%@-區(qū)subLocality:%@-省administrativeArea:%@-路thoroughfare:%@",placemark.name,placemark.locality,placemark.subLocality,placemark.administrativeArea,placemark.thoroughfare); }];
這時候就已經(jīng)可以獲取到具體的國家、省、市、區(qū)、街道了。
補充:反編碼是獲取不到POI位置的(我獲取不到)。這時候可以使用
self.placesClient = [GMSPlacesClient sharedClient];//獲取某個地點的具體信息 [self.placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *likelihoodList, NSError *error) { if (error != nil) { DLog(@"Current Place error %@", [error localizedDescription]); return; } // for (GMSPlaceLikelihood *likelihood in likelihoodList.likelihoods) { // GMSPlace* place = likelihood.place; // NSLog(@"Current Place name %@ at likelihood %g", place.name, likelihood.likelihood); // NSLog(@"Current Place address %@", place.formattedAddress); // NSLog(@"Current Place attributions %@", place.attributions); // NSLog(@"Current PlaceID %@", place.placeID); // } //這里就可以獲取到POI的名字了 //這里做一些你想做的事 }];
點擊地圖并移動大頭針
這里是用到GMSMapViewDelegate的代理回調(diào)
回調(diào)1:這里是點擊地圖上的某個點API返回的代理方法,在這個代理方法,你可以獲取經(jīng)緯度去反編譯地址
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate{ //點擊一次先清除上一次的大頭針 [self.marker.map clear]; self.marker.map = nil; // 通過location 或得到當(dāng)前位置的經(jīng)緯度 GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:coordinate.latitude longitude:coordinate.longitude zoom:Level]; CLLocationCoordinate2D position2D = CLLocationCoordinate2DMake(coordinate.latitude,coordinate.longitude); self.mapView.camera = camera; //大頭針 self.marker = [GMSMarker markerWithPosition:position2D]; self.marker.map = self.mapView; CLLocation *curLocation = [[CLLocation alloc]initWithLatitude:coordinate.latitude longitude:coordinate.longitude]; CLGeocoder *geocoder = [[CLGeocoder alloc]init]; //反地理編碼 [geocoder reverseGeocodeLocation:curLocation completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) { if (error) { DLog(@"error.description:%@",error.description); }else{ CLPlacemark *placemark = [placemarks objectAtIndex:0]; //賦值詳細(xì)地址 DLog(@"placemark---路號name:%@-市l(wèi)ocality:%@-區(qū)subLocality:%@-省administrativeArea:%@-路thoroughfare:%@",placemark.name,placemark.locality,placemark.subLocality,placemark.administrativeArea,placemark.thoroughfare); }]; }
回調(diào)2:這里也是點擊地圖上的某個點API返回的代理方法
- (void)mapView:(GMSMapView *)mapView didTapPOIWithPlaceID:(NSString *)placeID name:(NSString *)name location:(CLLocationCoordinate2D)location{ }
tips:值得注意的,兩者的區(qū)別是:第二個點擊代理方法是當(dāng)你點擊POI的時候才會回調(diào),會返回place的name、ID、經(jīng)緯度;第一個代理方法是只要點擊地圖任意一個位置就會回調(diào),只會返回經(jīng)緯度。也就是:每一次的點擊,只會執(zhí)行其中一個代理方法。
搜索:
搜索功能在官方文檔是叫做“自動完成”,即你輸入一部分的文本,GoogleMap會根據(jù)你的文本預(yù)測出地點并自動填充返回,具體請看官方文檔自動完成
效果如圖:
這里你需要做的步驟跟做“定位”的一樣:
(1)獲取APIKEY
(2) 在application:didFinishLaunchingWithOptions: 注冊密匙
1[GMSPlacesClient provideAPIKey:@"YOUR_API_KEY"];
(3) 創(chuàng)建搜索UI并調(diào)用代理方法獲取API自動填充的結(jié)果數(shù)組集
小坑提示: GMSPlacesClient跟GMSServices的密匙是不一樣的,密匙不對的話,會出現(xiàn)反復(fù)調(diào)用
viewController:didFailAutocompleteWithError:的現(xiàn)象。
tips:搭建搜索UI又幾種方式:1)搜索框直接創(chuàng)建在導(dǎo)航欄 2)搜索欄創(chuàng)建在視圖頂部 3)自定義。根據(jù)你的需求用代碼~
(一)這里是第一種方式(搜索框直接創(chuàng)建在導(dǎo)航欄):
GMSAutocompleteViewController *acController = [[GMSAutocompleteViewController alloc] init]; acController.delegate = self; [self presentViewController:acController animated:YES completion:nil];
tips:這里就可以直接往搜索框編輯文字,API會直接給你返回搜索結(jié)果集合
(二)調(diào)用API代理方法:
// Handle the user's selection. 這是用戶選擇搜索中的某個地址后返回的結(jié)果回調(diào)方法 - (void)viewController:(GMSAutocompleteViewController *)viewController didAutocompleteWithPlace:(GMSPlace *)place { [self dismissViewControllerAnimated:YES completion:nil]; [self.marker.map clear]; self.marker.map = nil; // 通過location 或得到當(dāng)前位置的經(jīng)緯度 GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:place.coordinate.latitude longitude:place.coordinate.longitude zoom:Level]; CLLocationCoordinate2D position2D = CLLocationCoordinate2DMake(place.coordinate.latitude,place.coordinate.longitude); self.marker = [GMSMarker markerWithPosition:position2D]; self.mapView.camera = camera; self.marker.map = self.mapView; self.locationLabel.text = place.name; self.locationDetailLabel.text = place.formattedAddress; }
tips:這個代理方法實現(xiàn)的是,當(dāng)用戶在搜索集中選擇了在某一個結(jié)果返回地圖,并定位添加大頭針。
自動填充失敗的回調(diào):
- (void)viewController:(GMSAutocompleteViewController *)viewController didFailAutocompleteWithError:(NSError *)error { [self dismissViewControllerAnimated:YES completion:nil]; // TODO: handle the error. DLog(@"Error: %@", [error description]); }
tips:自動填充失敗后你可以在這里做一些事,默認(rèn)是不管的。
補充:搜索欄的外觀是可以自定義的,你可以設(shè)置成跟自己的app一樣的風(fēng)格~具體請看設(shè)置 UI 控件樣式屬性
到這里,搜索功能就算完成了。
相關(guān)文章
iOS應(yīng)用中使用Auto Layout實現(xiàn)自定義cell及拖動回彈
這篇文章主要介紹了iOS應(yīng)用中使用Auto Layout實現(xiàn)自定義cell及拖動回彈的方法,自定義UITableViewCell并使用Auto Layout對其進行約束可以方便地針對多尺寸屏幕進行調(diào)整,代碼為Swift語言,需要的朋友可以參考下2016-03-03詳解IOS開發(fā)之實現(xiàn)App消息推送(最新)
這篇文章主要介紹了詳解IOS開發(fā)之實現(xiàn)App消息推送(最新),具有一定的參考價值,有興趣的可以了解一下。2016-12-12你應(yīng)該知道的tableViewCell行高計算處理
這篇文章主要給大家介紹了關(guān)于tableViewCell行高計算的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12IOS中NSPredicate和NSRegularExpression校驗正則表達(dá)式區(qū)別
本文文章通過實例代碼給大家講述了在IOS開發(fā)中NSPredicate和NSRegularExpression校驗正則表達(dá)式區(qū)別,需要的朋友趕快學(xué)習(xí)下吧。2018-01-01