iOS Google地圖開發小結(2017)

火之玉發表於2017-10-11

原文: 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截圖;

Places API官方demo截圖
Places API官方demo截圖

section0: (Autocomplete)

Autocomplete
Autocomplete

Autocomplete主要功能是搜尋相關的位置資訊(文字方式);
裡面還會展示UISearchBar/UISearchViewController的幾種呈現方法, 感興趣的可以看看;

section1: (Programmatic APIs)

Programmatic APIs
Programmatic APIs

Programmatic APIs主要展示搜尋或所選點附近的資訊(地圖方式);

2.Maps SDK for iOS

重點介紹內容, mark, mark....
還是一樣, 先看下官方demo, 大概瀏覽一下Google地圖的功能;

//基本組成部分
Map(地圖): 基本的地圖建立, 元件, 類別等;
Panorama(全景): 固定/可旋轉的街景;
Overlays(覆蓋物): 地圖檢視的自定義(地圖大頭針, 彈出資訊框等);
Camera(攝像頭): 當前地圖的可視範圍(設定攝像頭中心點座標、鏡頭縮放比例、方向、視角等);
Services(服務): 地理編碼/逆地理編碼;複製程式碼

結構概覽:

Maps SDK Demos 結構概覽
Maps SDK Demos 結構概覽

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:開啟/關閉特定檢視。 可以設定為:satellitetraffictransit。 可以使用逗號分隔符來設定多個值。 如果指定了不帶任何值的引數,那麼將清除所有的檢視。
  • zoom:指定地圖的縮放級別。
    //示例 URL,它以紐約為中心、採用 14 級縮放級別來顯示地圖,且開啟了交通檢視
    comgooglemaps://?center=40.765819,-73.975866&zoom=14&views=traffic複製程式碼

2.3.3 搜尋
引數:

  • q:用於搜尋的查詢字串。
    //示例 URL 用來在指定位置附近搜尋“Pizza"
    comgooglemaps://?q=Pizza&center=37.759748,-122.427135複製程式碼

2.3.4 顯示路線
引數:

  • saddr:設定路線搜尋的起點。 它可以是一個緯度、經度或查詢格式的地址。 如果它是返回多個結果的查詢字串, 將選擇第一個結果。 如果該值留空,那麼將使用該使用者的當前位置。
  • daddr:設定路線搜尋的終點。 具有與 saddr 相同的格式和行為。
  • directionsmode:交通方式。 可以設定為:drivingtransitbicyclingwalking
    // 示例 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複製程式碼
    2.3.5 指定回撥URL
    引數:
  • x-source – 傳送 x-callback 請求的應用的名稱。 最好使用短名稱。
  • x-success – 完成時呼叫的 URL。 通常,這是您自己的應用的 URL 架構,可以讓使用者返回到原來的應用。
    // 示例將啟動 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複製程式碼
    2.3.6 嚮應用新增導航
    // 程式碼展示瞭如何使用 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--谷歌地圖相關功能的實現

相關文章