最近接觸了一個(gè)international的項(xiàng)目, 用到Google地圖, 在此稍微總結(jié)一下, 方便以后使用;
一. 準(zhǔn)備工作
相關(guān)資料:
Google地圖API
官方Google地圖API
SMCalloutView
這個(gè)是點(diǎn)擊大頭針彈出信息框的自定義視圖, 官方地圖自定義有局限性, 下面??會(huì)講到, 示例如圖:
二.開發(fā)內(nèi)容
對(duì)于iOS開發(fā)者, Google地圖提供了兩個(gè)開發(fā)入口:
Maps SDK for iOS
添加 Google 地圖
Places API for iOS
添加位置的最新信息
1.Places API for iOS
這個(gè)一般開發(fā)Google地圖用不到, 不過還是簡單說一下, 官方demo截圖;
section0: (Autocomplete)
Autocomplete主要功能是搜索相關(guān)的位置信息(文本方式);
里面還會(huì)展示UISearchBar/UISearchViewController的幾種呈現(xiàn)方法, 感興趣的可以看看;
section1: (Programmatic APIs)
Programmatic APIs主要展示搜索或所選點(diǎn)附近的信息(地圖方式);
2.Maps SDK for iOS
重點(diǎn)介紹內(nèi)容, mark, mark....
還是一樣, 先看下官方demo, 大概瀏覽一下Google地圖的功能;
//基本組成部分
Map(地圖): 基本的地圖創(chuàng)建, 組件, 類別等;
Panorama(全景): 固定/可旋轉(zhuǎn)的街景;
Overlays(覆蓋物): 地圖視圖的自定義(地圖大頭針, 彈出信息框等);
Camera(攝像頭): 當(dāng)前地圖的可視范圍(設(shè)置攝像頭中心點(diǎn)坐標(biāo)断凶、鏡頭縮放比例、方向巫俺、視角等);
Services(服務(wù)): 地理編碼/逆地理編碼;
結(jié)構(gòu)概覽:
2.1 常用類介紹:
GMSMapView 最主要的地圖類
GMSCameraPosition 地圖攝像頭认烁,可以理解為當(dāng)前地圖的可視范圍,可以獲取到攝像頭中心點(diǎn)坐標(biāo)介汹、鏡頭縮放比例却嗡、方向、視角等參數(shù)
GMSMarker 地圖大頭針
GMSGeocoder 反向地理編碼類
GMSAddress 反向地理編碼返回的類,包含坐標(biāo)及地理位置描述等信息
CLLocationManager 就是CoreLocation框架下的地理位置管理類
GMSAutocompleteFetcher 搜索自動(dòng)補(bǔ)全抓取器嘹承,通過該類的代理方法實(shí)現(xiàn)搜索自動(dòng)補(bǔ)全
2.2 常用方法介紹:
GMSMapViewDelegate
:
mapView:willMove: 鏡頭即將移動(dòng)時(shí)調(diào)用
mapView:didChangeCameraPosition:鏡頭移動(dòng)完成后調(diào)用mapView:didTapAtCoordinate: 點(diǎn)擊地圖時(shí)調(diào)用
mapView:didLongPressAtCoordinate: 長按地圖時(shí)調(diào)用
mapView:didTapMarker: 點(diǎn)擊大頭針時(shí)調(diào)用
mapView:didTapInfoWindowOfMarker: 點(diǎn)擊大頭針的彈出視窗時(shí)調(diào)用
mapView:didLongPressInfoWindowOfMarker: 長按大頭針視窗時(shí)調(diào)用
mapView:markerInfoWindow: 自定義大頭針彈出視窗窗价,返回UIView
mapView:didCloseInfoWindowOfMarker: 自定義大頭針彈出視窗關(guān)閉時(shí)調(diào)用
mapView:didDragMarker: 拖拽大頭針時(shí)調(diào)用
didTapMyLocationButtonForMapView: 點(diǎn)擊定位大頭針, 返回BOOL值
2.3 Google Maps URL 架構(gòu)(單獨(dú)介紹一下):
確實(shí)與國內(nèi)不同, Google地圖URL架構(gòu)沒在demo中提及;
??介紹一下:
iOS 版 Google Maps 應(yīng)用支持以下 URL 架構(gòu):
-
comgooglemaps://
和comgooglemaps-x-callback://
– 這些架構(gòu)允許您啟動(dòng) iOS 版 Google Maps 應(yīng)用,并執(zhí)行下列幾項(xiàng)操作之一:- 以指定的縮放級(jí)別顯示指定位置的地圖叹卷。
- 搜索位置或地點(diǎn)撼港,并將它們顯示在地圖上。
- 請(qǐng)求從一個(gè)位置前往另一個(gè)位置的路線骤竹。 可以返回以下四種交通方式的路線:駕車帝牡、步行、騎自行車和乘坐公共交通工具蒙揣。
- 向應(yīng)用添加導(dǎo)航靶溜。
- 當(dāng)應(yīng)用完成后,使用 comgooglemaps-x-callback://
發(fā)出一個(gè)回調(diào)懒震。 回調(diào)經(jīng)常用來使用戶返回到最初打開 iOS 版 Google Maps 的應(yīng)用墨技。
-
comgooglemapsurl://
– 此架構(gòu)允許您使用從桌面 Google Maps 網(wǎng)站得到的 URL 啟動(dòng) iOS 版 Google Maps 應(yīng)用。 這意味著您可以為用戶提供原生移動(dòng)體驗(yàn)挎狸,而不是簡單地加載 Google Maps 網(wǎng)站。- 原始 URL 可以是 maps.google.com断楷,或者 google.com/maps锨匆,也可以使用任何有效的國家代碼頂級(jí)域名來代替 com。
- 您還可以傳遞 goo.gl/maps 重定向 URL冬筒。
您可以將 x-source 和 x-success 參數(shù)與 comgooglemapsurl:// URL 架構(gòu)結(jié)合使用來發(fā)出回調(diào)恐锣。
2.3.1 檢查設(shè)備上是否已安裝 Google Maps 應(yīng)用;
if ([[UIApplication sharedApplication] canOpenURL:
[NSURL URLWithString:@"comgooglemaps://"]]) {
//已安裝Google地圖APP
} else {
//未安裝Google地圖APP
}
2.3.2 顯示地圖
參數(shù):
-
center
:這是地圖視口中心點(diǎn)。 其格式為用逗號(hào)分隔的字符串latitude
,longitude
舞痰。 -
mapmode
:設(shè)置所顯示地圖的種類土榴。 可以設(shè)置為:standard 或 streetview。 如果未指定响牛,則將使用當(dāng)前的應(yīng)用設(shè)置玷禽。 -
views
:開啟/關(guān)閉特定視圖赫段。 可以設(shè)置為:satellite
、traffic
或transit
矢赁。 可以使用逗號(hào)分隔符來設(shè)置多個(gè)值糯笙。 如果指定了不帶任何值的參數(shù),那么將清除所有的視圖撩银。 -
zoom
:指定地圖的縮放級(jí)別给涕。
//示例 URL,它以紐約為中心额获、采用 14 級(jí)縮放級(jí)別來顯示地圖够庙,且開啟了交通視圖
comgooglemaps://?center=40.765819,-73.975866&zoom=14&views=traffic
2.3.3 搜索
參數(shù):
-
q
:用于搜索的查詢字符串。
//示例 URL 用來在指定位置附近搜索“Pizza"
comgooglemaps://?q=Pizza¢er=37.759748,-122.427135
2.3.4 顯示路線
參數(shù):
-
saddr
:設(shè)置路線搜索的起點(diǎn)抄邀。 它可以是一個(gè)緯度耘眨、經(jīng)度或查詢格式的地址。 如果它是返回多個(gè)結(jié)果的查詢字符串撤摸, 將選擇第一個(gè)結(jié)果毅桃。 如果該值留空,那么將使用該用戶的當(dāng)前位置准夷。 -
daddr
:設(shè)置路線搜索的終點(diǎn)钥飞。 具有與saddr
相同的格式和行為。 -
directionsmode
:交通方式衫嵌。 可以設(shè)置為:driving
读宙、transit
、bicycling
或walking
楔绞。
// 示例 URL 用來顯示 Google 紐約辦事處與肯尼迪國際機(jī)場之間的交通路線
comgooglemaps://?saddr=Google+Inc,+8th+Avenue,+New+York,+NY&daddr=John+F.+Kennedy+International+Airport,+Van+Wyck+Expressway,+Jamaica,+New+York&directionsmode=transit
2.3.5 指定回調(diào)URL
參數(shù):
-
x-source
– 發(fā)送x-callback
請(qǐng)求的應(yīng)用的名稱结闸。 最好使用短名稱。 -
x-success
– 完成時(shí)調(diào)用的 URL酒朵。 通常桦锄,這是您自己的應(yīng)用的 URL 架構(gòu),可以讓用戶返回到原來的應(yīng)用蔫耽。
// 示例將啟動(dòng) iOS 版 Google Maps 應(yīng)用结耀,并以紐約為中心顯示地圖。 該應(yīng)用還會(huì)顯示標(biāo)有“SourceApp”的按鈕匙铡。 當(dāng)點(diǎn)擊“SourceApp”按鈕時(shí)图甜,iOS 版 Google Maps 應(yīng)用將發(fā)出一個(gè)指向虛擬的 URL 架構(gòu)的回調(diào), sourceapp://?resume=true.
comgooglemaps-x-callback://?center=40.765819,-73.975866&zoom=14
&x-success=sourceapp://?resume=true
&x-source=SourceApp
2.3.6 向應(yīng)用添加導(dǎo)航
// 代碼展示了如何使用 comgooglemaps-x-callback:// 架構(gòu)來請(qǐng)求路線鳖眼,然后在您的用戶準(zhǔn)備就緒后返回到您的應(yīng)用黑毅。 該代碼將執(zhí)行以下操作
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.");
}
該代碼將執(zhí)行以下操作:
- 驗(yàn)證 comgooglemaps-x-callback:// URL 架構(gòu)是否可用。
- 啟動(dòng) iOS 版 Google Maps 應(yīng)用钦讳,并請(qǐng)求前往紐約市肯尼迪國際機(jī)場的路線矿瘦。 將起始地址留空即可請(qǐng)求從用戶的當(dāng)前位置出發(fā)的路線枕面。
- 將標(biāo)記為“AirApp”的按鈕添加到 iOS 版 Google Maps 應(yīng)用中。 該按鈕標(biāo)簽由 x-source 參數(shù)定義匪凡。
- 當(dāng)用戶點(diǎn)擊返回按鈕時(shí)膊畴,調(diào)用虛擬 URL 架構(gòu) sourceapp://,。
三.遇到的問題
開發(fā)中難免遇到一些稀奇古怪的問題, 這里就著我遇到的問題分享一下;
需求:
實(shí)現(xiàn)一個(gè)自定義的彈窗, 要求點(diǎn)擊彈窗左邊視圖返回上一頁, 點(diǎn)擊右邊視圖跳轉(zhuǎn)導(dǎo)航功能;
問題:
在mapView:markerInfoWindow:
中我自定義了一個(gè)氣泡視圖, 視圖左右各一個(gè)按鈕, 按鈕的點(diǎn)擊方法被屏蔽, 只響應(yīng)了整個(gè)氣泡視圖的點(diǎn)擊方法(mapView:didTapInfoWindowOfMarker:
);
解決辦法:
在試了n個(gè)方法后, 終于讓我找到了SMCalloutView, github上的一個(gè)自定義氣泡的三方, 可以自由定義左右,中間, 背景視圖, 非常棒??, O(∩_∩)O哈哈~
首先是基礎(chǔ)操作:
#import <SMCalloutView/SMCalloutView.h>
static const CGFloat CalloutYOffset = 10.0f;
@interface ViewController ()
@property (strong, nonatomic) SMCalloutView *calloutView;
@property (strong, nonatomic) UIView *emptyCalloutView;
@end
之后初始化SMCalloutView
, 創(chuàng)建一個(gè)空View;
- (void)viewDidLoad
{
self.calloutView = [[SMCalloutView alloc] init];
self.calloutView.contentView = [UIView new];
self.emptyCalloutView = [[UIView alloc] initWithFrame:CGRectZero];
}
其次是GMSMapViewDelegate里面的設(shè)置:
- (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];
//取消默認(rèn)背景
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;
}
結(jié)果就可以在點(diǎn)擊方法里面盡情的調(diào)用了:
//左邊按鈕點(diǎn)擊方法
- (void)leftButtonClick:(UIButton *)button{
}
//右邊按鈕點(diǎn)擊方法
- (void)rightButtonClick:(UIButton *)button{
}
最后感謝這位網(wǎng)友的分享, 附上鏈接:
stackoverflow網(wǎng)友的分享
關(guān)于Google地圖開發(fā):
iOS Google地圖SDK入門教程
iOS--谷歌地圖相關(guān)功能的實(shí)現(xiàn)