原文: www.jianshu.com/p/7c1293ee8…
最近接觸了一個international的專案, 用到Google地圖, 在此稍微總結一下, 方便以後使用;
一. 準備工作
開發Google地圖當然離不開翻牆了, 先分享幾個好用的免費翻牆軟體:
1.軟體:
lantern
(For Window, Mac, Android, Ubuntu)
LetsVPN(appStore直接下載)
(For iOS)
2.相關資料:
Google地圖API
官方Google地圖API
SMCalloutView
這個是點選大頭針彈出資訊框的自定義檢視, 官方地圖自定義有侷限性, 下面?會講到, 示例如圖:
二.開發內容
對於iOS開發者, Google地圖提供了兩個開發入口:
Maps SDK for iOS
新增 Google 地圖
Places API for iOS
新增位置的最新資訊
1.Places API for iOS
這個一般開發Google地圖用不到, 不過還是簡單說一下, 官方demo截圖;
section0: (Autocomplete)
Autocomplete主要功能是搜尋相關的位置資訊(文字方式);
裡面還會展示UISearchBar/UISearchViewController的幾種呈現方法, 感興趣的可以看看;
section1: (Programmatic APIs)
Programmatic APIs主要展示搜尋或所選點附近的資訊(地圖方式);
2.Maps SDK for iOS
重點介紹內容, mark, mark....
還是一樣, 先看下官方demo, 大概瀏覽一下Google地圖的功能;
//基本組成部分
Map(地圖): 基本的地圖建立, 元件, 類別等;
Panorama(全景): 固定/可旋轉的街景;
Overlays(覆蓋物): 地圖檢視的自定義(地圖大頭針, 彈出資訊框等);
Camera(攝像頭): 當前地圖的可視範圍(設定攝像頭中心點座標、鏡頭縮放比例、方向、視角等);
Services(服務): 地理編碼/逆地理編碼;複製程式碼
結構概覽:
2.1 常用類介紹:
GMSMapView 最主要的地圖類
GMSCameraPosition 地圖攝像頭,可以理解為當前地圖的可視範圍,可以獲取到攝像頭中心點座標、鏡頭縮放比例、方向、視角等引數
GMSMarker 地圖大頭針
GMSGeocoder 反向地理編碼類
GMSAddress 反向地理編碼返回的類,包含座標及地理位置描述等資訊
CLLocationManager 就是CoreLocation框架下的地理位置管理類
GMSAutocompleteFetcher 搜尋自動補全抓取器,通過該類的代理方法實現搜尋自動補全複製程式碼
2.2 常用方法介紹:
GMSMapViewDelegate
:
mapView:willMove: 鏡頭即將移動時呼叫
mapView:didChangeCameraPosition:鏡頭移動完成後呼叫mapView:didTapAtCoordinate: 點選地圖時呼叫
mapView:didLongPressAtCoordinate: 長按地圖時呼叫
mapView:didTapMarker: 點選大頭針時呼叫
mapView:didTapInfoWindowOfMarker: 點選大頭針的彈出視窗時呼叫
mapView:didLongPressInfoWindowOfMarker: 長按大頭針視窗時呼叫
mapView:markerInfoWindow: 自定義大頭針彈出視窗,返回UIView
mapView:didCloseInfoWindowOfMarker: 自定義大頭針彈出視窗關閉時呼叫
mapView:didDragMarker: 拖拽大頭針時呼叫
didTapMyLocationButtonForMapView: 點選定位大頭針, 返回BOOL值複製程式碼
2.3 Google Maps URL 架構(單獨介紹一下):
確實與國內不同, Google地圖URL架構沒在demo中提及;
?介紹一下:
iOS 版 Google Maps 應用支援以下 URL 架構:
comgooglemaps://
和comgooglemaps-x-callback://
– 這些架構允許您啟動 iOS 版 Google Maps 應用,並執行下列幾項操作之一:
- 以指定的縮放級別顯示指定位置的地圖。
- 搜尋位置或地點,並將它們顯示在地圖上。
- 請求從一個位置前往另一個位置的路線。 可以返回以下四種交通方式的路線:駕車、步行、騎自行車和乘坐公共交通工具。
- 嚮應用新增導航。
- 當應用完成後,使用 comgooglemaps-x-callback:// 發出一個回撥。 回撥經常用來使使用者返回到最初開啟 iOS 版 Google Maps 的應用。
comgooglemapsurl://
– 此架構允許您使用從桌面 Google Maps 網站得到的 URL 啟動 iOS 版 Google Maps 應用。 這意味著您可以為使用者提供原生移動體驗,而不是簡單地載入 Google Maps 網站。
- 原始 URL 可以是 maps.google.com,或者 google.com/maps,也可以使用任何有效的國家程式碼頂級域名來代替 com。
- 您還可以傳遞 goo.gl/maps 重定向 URL。
您可以將 x-source 和 x-success 引數與 comgooglemapsurl:// URL 架構結合使用來發出回撥。
2.3.1 檢查裝置上是否已安裝 Google Maps 應用;
if ([[UIApplication sharedApplication] canOpenURL:
[NSURL URLWithString:@"comgooglemaps://"]]) {
//已安裝Google地圖APP
} else {
//未安裝Google地圖APP
}複製程式碼
2.3.2 顯示地圖
引數:
center
:這是地圖視口中心點。 其格式為用逗號分隔的字串latitude
,longitude
。mapmode
:設定所顯示地圖的種類。 可以設定為:standard 或 streetview。 如果未指定,則將使用當前的應用設定。views
:開啟/關閉特定檢視。 可以設定為:satellite
、traffic
或transit
。 可以使用逗號分隔符來設定多個值。 如果指定了不帶任何值的引數,那麼將清除所有的檢視。zoom
:指定地圖的縮放級別。//示例 URL,它以紐約為中心、採用 14 級縮放級別來顯示地圖,且開啟了交通檢視
comgooglemaps://?center=40.765819,-73.975866&zoom=14&views=traffic複製程式碼
2.3.3 搜尋
引數:
q
:用於搜尋的查詢字串。//示例 URL 用來在指定位置附近搜尋“Pizza"
comgooglemaps://?q=Pizza¢er=37.759748,-122.427135複製程式碼
2.3.4 顯示路線
引數:
saddr
:設定路線搜尋的起點。 它可以是一個緯度、經度或查詢格式的地址。 如果它是返回多個結果的查詢字串, 將選擇第一個結果。 如果該值留空,那麼將使用該使用者的當前位置。daddr
:設定路線搜尋的終點。 具有與saddr
相同的格式和行為。directionsmode
:交通方式。 可以設定為:driving
、transit
、bicycling
或walking
。
2.3.5 指定回撥URL// 示例 URL 用來顯示 Google 紐約辦事處與肯尼迪國際機場之間的交通路線
comgooglemaps://?saddr=Google+Inc,+8th+Avenue,+New+York,+NY&daddr=John+F.+Kennedy+International+Airport,+Van+Wyck+Expressway,+Jamaica,+New+York&directionsmode=transit複製程式碼
引數:x-source
– 傳送x-callback
請求的應用的名稱。 最好使用短名稱。x-success
– 完成時呼叫的 URL。 通常,這是您自己的應用的 URL 架構,可以讓使用者返回到原來的應用。
2.3.6 嚮應用新增導航// 示例將啟動 iOS 版 Google Maps 應用,並以紐約為中心顯示地圖。 該應用還會顯示標有“SourceApp”的按鈕。 當點選“SourceApp”按鈕時,iOS 版 Google Maps 應用將發出一個指向虛擬的 URL 架構的回撥, sourceapp://?resume=true.
comgooglemaps-x-callback://?center=40.765819,-73.975866&zoom=14
&x-success=sourceapp://?resume=true
&x-source=SourceApp複製程式碼
該程式碼將執行以下操作:// 程式碼展示瞭如何使用 comgooglemaps-x-callback:// 架構來請求路線,然後在您的使用者準備就緒後返回到您的應用。 該程式碼將執行以下操作
NSURL *testURL = [NSURL URLWithString:@"comgooglemaps-x-callback://"];
if ([[UIApplication sharedApplication] canOpenURL:testURL]) {
NSString *directionsRequest = @"comgooglemaps-x-callback://" +
@"?daddr=John+F.+Kennedy+International+Airport,+Van+Wyck+Expressway,+Jamaica,+New+York" +
@"&x-success=sourceapp://?resume=true&x-source=AirApp";
NSURL *directionsURL = [NSURL URLWithString:directionsRequest];
[[UIApplication sharedApplication] openURL:directionsURL];
} else {
NSLog(@"Can't use comgooglemaps-x-callback:// on this device.");
}複製程式碼- 驗證 comgooglemaps-x-callback:// URL 架構是否可用。
- 啟動 iOS 版 Google Maps 應用,並請求前往紐約市肯尼迪國際機場的路線。 將起始地址留空即可請求從使用者的當前位置出發的路線。
- 將標記為“AirApp”的按鈕新增到 iOS 版 Google Maps 應用中。 該按鈕標籤由 x-source 引數定義。
- 當使用者點選返回按鈕時,呼叫虛擬 URL 架構 sourceapp://,。
三.遇到的問題
開發中難免遇到一些稀奇古怪的問題, 這裡就著我遇到的問題分享一下;
需求:
實現一個自定義的彈窗, 要求點選彈窗左邊檢視返回上一頁, 點選右邊檢視跳轉導航功能;
問題:
在mapView:markerInfoWindow:
中我自定義了一個氣泡檢視, 檢視左右各一個按鈕, 按鈕的點選方法被遮蔽, 只響應了整個氣泡檢視的點選方法(mapView:didTapInfoWindowOfMarker:
);
解決辦法:
在試了n個方法後, 終於讓我找到了SMCalloutView, github上的一個自定義氣泡的三方, 可以自由定義左右,中間, 背景檢視, 非常棒?, O(∩_∩)O哈哈~
首先是基礎操作:
#import <SMCalloutView/SMCalloutView.h>
static const CGFloat CalloutYOffset = 10.0f;
@interface ViewController ()
@property (strong, nonatomic) SMCalloutView *calloutView;
@property (strong, nonatomic) UIView *emptyCalloutView;
@end複製程式碼
之後初始化SMCalloutView
, 建立一個空View;
- (void)viewDidLoad
{
self.calloutView = [[SMCalloutView alloc] init];
self.calloutView.contentView = [UIView new];
self.emptyCalloutView = [[UIView alloc] initWithFrame:CGRectZero];
}複製程式碼
其次是GMSMapViewDelegate裡面的設定:
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker {
CLLocationCoordinate2D anchor = marker.position;
CGPoint point = [mapView.projection pointForCoordinate:anchor];
self.calloutView.calloutOffset = CGPointMake(0, -CalloutYOffset);
//SMCalloutView中contentView
UIView *googleTipView = [UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 50);
//左方按鈕
UIButton *leftButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[googleTipView addSubview:bView];
[leftButton addTarget:self action:@selector(leftButtonClick:) forControlEvents:UIControlEventTouchUpInside];
//右方按鈕
UIButton *rightButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 0, 100, 50)];
[googleTipView addSubview:bView];
[rightButton addTarget:self action:@selector(rightButtonClick:) forControlEvents:UIControlEventTouchUpInside];
//取消預設背景
SMCalloutBackgroundView *calloutBgView = [[SMCalloutBackgroundView alloc] initWithFrame:CGRectZero];
self.calloutView.backgroundView = calloutBgView;
self.calloutView.contentView = googleTipView;
self.calloutView.hidden = NO;
CGRect calloutRect = CGRectZero;
calloutRect.origin = point;
calloutRect.size = CGSizeZero;
[self.calloutView presentCalloutFromRect:calloutRect
inView:mapView
constrainedToView:mapView
animated:YES];
return self.emptyCalloutView;
}
- (void)mapView:(GMSMapView *)pMapView didChangeCameraPosition:(GMSCameraPosition *)position {
if (pMapView.selectedMarker != nil && !self.calloutView.hidden) {
CLLocationCoordinate2D anchor = [pMapView.selectedMarker position];
CGPoint arrowPt = self.calloutView.backgroundView.arrowPoint;
CGPoint pt = [pMapView.projection pointForCoordinate:anchor];
pt.x -= arrowPt.x;
pt.y -= arrowPt.y + CalloutYOffset;
self.calloutView.frame = (CGRect) {.origin = pt, .size = self.calloutView.frame.size };
} else {
self.calloutView.hidden = YES;
}
}
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
self.calloutView.hidden = YES;
}
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
mapView.selectedMarker = marker;
return YES;
}複製程式碼
結果就可以在點選方法裡面盡情的呼叫了:
//左邊按鈕點選方法
- (void)leftButtonClick:(UIButton *)button{
}
//右邊按鈕點選方法
- (void)rightButtonClick:(UIButton *)button{
}複製程式碼
最後感謝這位網友的分享, 附上鍊接:
stackoverflow網友的分享
關於Google地圖開發:
iOS Google地圖SDK入門教程
iOS--谷歌地圖相關功能的實現