iOSGoogle地圖開發小結(2017)

NO IMAGE

原文: 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
這個是點擊大頭針彈出信息框的自定義視圖, 官方地圖自定義有侷限性, 下面👇會講到, 示例如圖:

iOSGoogle地圖開發小結(2017)
自定義視圖

二.開發內容

對於iOS開發者, Google地圖提供了兩個開發入口:
Maps SDK for iOS
添加 Google 地圖

Places API for iOS
添加位置的最新信息

1.Places API for iOS

這個一般開發Google地圖用不到, 不過還是簡單說一下, 官方demo截圖;

iOSGoogle地圖開發小結(2017)
Places API官方demo截圖

section0: (Autocomplete)

iOSGoogle地圖開發小結(2017)
Autocomplete

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

section1: (Programmatic APIs)

iOSGoogle地圖開發小結(2017)
Programmatic APIs

Programmatic APIs主要展示搜索或所選點附近的信息(地圖方式);

2.Maps SDK for iOS

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

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

結構概覽:

iOSGoogle地圖開發小結(2017)
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--谷歌地圖相關功能的實現

相關文章

iOS製作電子簽章

Xcode與開發相關的功能,你真的的都瞭解嗎?

閒聊,程序猿的那些“趣事兒”

源碼剖析SVPullToRefresh