最近接触了一个international的项目, 用到Google地图, 在此稍微总结一下, 方便以后使用;
一. 准备工作
相关资料:
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
。
// 示例 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--谷歌地图相关功能的实现