《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

本节书摘来自异步社区《iOS组件与框架——iOS SDK高级特性剖析》一书中的第2章,第2.4节地图注释和覆盖层,作者 【美】Kyle Richter , Joe Keeley,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 地图注释和覆盖层
iOS组件与框架——iOS SDK高级特性剖析
地图视图(MKMapView)是一种可滚动的视图,行为独特;以标准方式在其中添加子视图时,子视图不会随地图视图滚动,而是静止的,其相对于地图视图框架的位置始终不变。对悬停按钮或标签来说,这种特点也许不错,但在地图上标出点和细节至关重要。要标出地图视图中感兴趣的点或区域,可使用地图注释和覆盖层。地图滚动或缩放时,注释和覆盖层在地图上的位置保持不变。地图注释是使用地图上的单个坐标点定义的,而地图覆盖层可以是线段、多边形或复杂形状。MapKit将注释(覆盖层)同其关联的视图区分开来。注释和覆盖层是数据,指定了相关联的视图应显示在地图的什么地方,这些数据被直接添加到地图视图中。在需要显示注释或覆盖层时,地图视图将请求相关联的视图,就像表视图根据需要为索引路径请求单元格一样。

2.4.1 添加注释
任何对象都可用作地图视图中的注释,前提条件是它实现了协议MKAnnotation。Apple建议注释对象应是轻量级的,因为对于添加的每个注释,地图视图都将包含一个指向它的引用;另外,如果注释太多,可能影响地图的滚动和缩放性能。如果注释非常简单,可使用MKPointAnnotation类。在示例应用中,ICFFavoritePlace实现了协议MKAnnotation,它是NSManagedObject的子类,因此可使用Core Data进行持久化。有关如何使用Core Data和NSManagedObject子类的更详细信息,请参阅第13章。

要实现协议MKAnnotation,类必须实现属性coordinate,地图视图将使用这个属性确定将注释放在地图的什么地方。属性coordinate的获取方法返回一个CLLocationCoordinate2D。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

由于ICFFavoritePlace类存储了地点的经度和纬度,因此属性coordinate的获取方法根据经度和纬度创建一个CLLocationCoordinate2D,这是使用Core Location提供的函数CLLocationCoordinate2DMake完成的。在属性coordinate的设置方法中,ICFFavoritePlace存储CLLocationCoordinate2D参数中的经度和纬度。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

协议MKAnnotation还定义了另外两个可选属性:title和subtitle。在用户轻按注释视图时,地图视图可使用这两个属性来显示标注(callout),如图2.7所示。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

在ICFMainViewController的方法viewDidLoad:中,调用了方法updateMapAnnotations来填充初始地图注释,在地点详情编辑视图被关闭时,也调用了这个方法。这个方法首先将地图视图的注释都删除。虽然注释不多时这种方式完全可行,但注释很多时,必须设计更智能的方式,以高效地删除不需要的注释并添加新的注释。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

2.4.2 显示标准和自定义的注释视图
注释视图在地图上表示注释。MapKit提供了两种标准注释视图:大头针(表示搜索到的位置)和蓝点(表示当前位置)。可使用静态图像定制注释视图,还可通过创建MKAnnotationView子类来全面定制注释视图。在示例应用中,在用户喜欢的地方显示标准大头针,在当前位置显示标准蓝点,而可拖曳的注释则使用绿色箭头表示,如图2.8所示。

为让地图视图显示注释视图,地图视图委托需要实现方法mapView:viewForAnnotation。在示例应用中,方法mapView:viewForAnnotation是在ICFMainViewController中实现的,它首先检查注释是否是当前位置。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

如果是当前位置,就返回nil,这让地图视图使用标准蓝点。接下来,这个方法检查注释的类型。如果注释表示的位置为下一个目的地(goingNext),就返回一个自定义注释视图,否则返回标准的大头针注释视图。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

为返回标准的大头针注释视图,这个方法首先尝试从队列中取出一个未用的注释视图。如果没有这样的注释视图,就创建一个MKPinAnnotationView实例。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

创建大头针注释视图后,就可对其进行定制了:设置大头针的颜色(可设置为红色、绿色或紫色)、指定用户轻按注释视图时是否显示说明、指定注释视图是否是可拖曳的。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

轻按注释视图显示的说明包含可定制的左扩展视图(accessory view)和右扩展视图。左扩展视图被设置为一幅自定义图像,而右扩展视图被设置为标准的展开按钮。如果左扩展视图或右扩展视图是从UIControl派生而来的对象,用户轻按它们时将调用委托方法mapView:annotation View:calloutAccessoryControlTapped:。

否则,开发人员应对这些对象进行配置,使其对轻按做出响应。请注意,Apple规定扩展视图的高度不能超过32像素。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

这种注释视图将显示为绿色箭头,而不是标准大头针,如图2.8所示。

2.4.3 可拖曳的注释视图
可拖曳的注释视图很有用,它让用户能够在地图上指定地点。在示例应用中,有个特殊的地点,它是用户的下一个目的地,用绿色箭头表示。可让注释视图是可拖曳的,为此可将其属性draggable设置为YES。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

这样,用户就可将它拖曳到地图的任何地方。为更详细地了解用户是如何拖曳注释视图的,地图视图委托实现了方法mapView:annotationView:didChangeDragState:fromOldState:。每当可拖曳注释视图的拖曳状态发生变化时,都将调用这个方法,并指出拖曳状态为无(MKAnnotationViewDragStateNone)、即将开始、正在拖曳、即将撤销还是即将结束。通过查看新的拖曳状态和旧的拖曳状态,可编写自定义逻辑来处理众多不同的拖曳情形。

在示例应用中,当用户停止拖曳绿色箭头时,将对箭头指定的新位置进行反向地理编码(这将在 2.5 节更详细地介绍),以获取新位置的名称和地址。为此,这个方法需要检查拖曳是否已结束。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

2.4.4 使用地图覆盖层
地图覆盖层类似于地图注释,可以是任何实现了协议MKOverlay的对象,而地图视图委托将负责提供与地图覆盖层相关联的视图。地图覆盖层不同于注释的地方在于,它们不仅可以表示点,还可以表示线段和形状,因此非常适合用于在地图上表示线路或感兴趣的区域。为演示地图覆盖层,示例应用提供了给喜欢的地点添加地理围栏的功能(这将在后面的2.6节更详细地介绍),围栏的半径由用户指定。给喜欢的地点添加地理围栏后,将在地图上显示一个圆,其半径是用户指定的值,圆心为喜欢的地点,如图2.9所示。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

前面的2.4.1节说过,方法updateMapAnnotations给地图添加注释;这个方法还给地图添加覆盖层。为此,它清除地图视图中的所有覆盖层。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层

由于仅当地点启用了地理围栏功能时,才需要为它显示覆盖层,因为这个方法迭代所有的地点,并为启用了地理围栏功能的地点添加覆盖层。


《iOS组件与框架——iOS SDK高级特性剖析》——第2章,第2.4节地图注释和覆盖层
上一篇:Python Qt GUI设计:如何调整组件布局比例?(拓展篇—1)


下一篇:HTTP 502: Whoops, GitLab is taking too much time to respond.