显示位置

许多iOS设备(如iPod Touch,iPad和iPhone)提供有关设备位置的信息。 iOS包括一个称为CoreLocation的框架,它抽象了如何检索位置,无论是通过Wi-Fi,蜂窝网络还是GPS。

arcgis框架还为开发人员提供了一个API,以将位置功能合并到其应用程序中,并根据其需求对其进行配置.

地图组件AGSMapView阻止开发人员处理CoreLocation框架的复杂性,并提供了一种显示和跟踪设备在地图上的位置的简单方法。 与地图关联的AGSLocationDisplay对象为CoreLocation框架提供了一个外观,使其更易于使用位置服务。

开始显示位置

在旧版操作系统(如iOS 7或更低版​​本)上,在地图上显示设备位置与在地图加载完成后调用AGSLocationDisplay对象上的startDataSource方法一样简单。

func mapViewDidLoad(mapView: AGSMapView!) {
	self.mapView.locationDisplay.startDataSource()
}

iOS8以上需要修改plist,请求权限,此处略去不提。

位置数据源

AGSLocationDisplay只管理地图上位置信息的显示。它不主动检索任何位置信息。相反,它依赖位置数据源来频繁提供位置更新。您可以使用任何提供的数据源,也可以插入自定义数据源以将位置更新提供给地图。

如果没有提供,则AGSLocationDisplay默认为AGSCLLocationManagerLocationDisplayDataSource。

AGSCLLocationManagerLocationDisplayDataSource

此数据源使用iOS CoreLocation框架通过GPS,WiFi或蜂窝网络检索位置更新。它试图尽可能频繁地检索最准确的信息。

AGSSimulatedLocationDisplayDataSource

此数据源允许您基于任何折线几何模拟位置更新。多段线中的每个顶点都用于触发位置更新。{?类似模拟导航?}

//The polyline geometry along which location updates should be simulated
let route:AGSPolyline = ...
        
//Create the data source. Assign the geometry.
let simulatedDS = AGSSimulatedLocationDisplayDataSource()
simulatedDS.setLocationsFromPolyline(route)
        
//Set data source
self.mapView.locationDisplay.dataSource = simulatedDS

AGSGPXLocationDataSource

此数据源使用GPX文件中的第一个轨道或路线来模拟位置更新。

//Create the data source using a GPX file on the web
let url = NSURL(string: "http://www.topografix.com/fells_loop.gpx")
let gpxDS = AGSGPXLocationDisplayDataSource(URL: url)
        
//Or, create the data source using a GPX file on the device
let pathToGPXOnDevice:String = ...
let gpxDS = AGSGPXLocationDisplayDataSource(path: pathToGPXOnDevice)
        
//Set data source
self.mapView.locationDisplay.dataSource = gpxDS

Autopan modes

该地图提供了许多预设,用于定义在接收位置更新时地图的行为方式。

Off mode

在这种模式下,地图只更新地图上位置符号的位置。它不重新居中。 因此,位置符号可能会离开屏幕以响应位置更新。

Default mode

在这种模式下,当符号移动到“漫游范围”之外时,地图试图通过重新定位位置符号来将位置符号保持在屏幕上。 因此,位置符号可以在漫游范围内自由移动,但只要符号退出漫游范围,地图就会重新居中符号。

默认情况下,漫游范围是地图可视范围大小的一半,但您可以通过修改AGSLocationDisplay上的wanderExtentFactor来自定义漫游范围。 值为1意味着漫游范围等于地图可见范围的大小,并且在地图重新居中之前,位置符号可以移动到地图的边缘。 值为0意味着无限小的漫游范围,并且地图重新集中于每个位置更新。

self.mapView.locationDisplay.autoPanMode = .Default
self.mapView.locationDisplay.wanderExtentFactor = 0.75

如果用户在此模式下平移地图,则模式会自动将Autopan模式更改为关闭,以防止用户与地图“对抗”,否则地图会根据未来的位置更新尝试重新居中。

此模式最适合车载导航。在此模式下,位置符号固定在屏幕上的一个点上,并始终指向设备的顶部边缘。地图根据位置更新以及设备行进方向进行平移和旋转。因此,位置符号显示为静止,而位于其下方的地图似乎在移动和旋转。

可以通过修改AGSLocationDisplay上的navigatonPointHeightFactor属性来调整位置符号的位置。值为0意味着位置符号应位于地图的底部边缘,1表示顶部边缘。介于0和1之间的值将该符号定位在沿着从底部边缘到顶部边缘的中心线的某处。

self.mapView.locationDisplay.autoPanMode = .Navigation
self.mapView.locationDisplay.wanderExtentFactor = 0.25

如果用户在此模式下平移地图,则模式会自动更改为关闭。

Compass Navigation mode

这种模式在用户走路时更好。与导航模式一样,位置符号固定在屏幕上的某个点上,并始终指向设备的顶部边缘。但是,地图根据用户的方位相对于磁北而旋转,而不是基于设备行进的方向,这是导航模式下的情况。因此,地图反映了用户在用户围绕他们的位置转动时所处的位置。

位置符号位置可以通过修改navigatonPointHeightFactor进行调整。值为0意味着位置符号应位于地图的底部边缘,1表示顶部边缘。介于0和1之间的值将符号置于底部和顶部边缘之间的某处。

self.mapView.locationDisplay.autoPanMode = .CompassNavigation
self.mapView.locationDisplay.wanderExtentFactor = 0.5

如果用户在此模式下平移地图,则模式会自动更改为关闭。

If your application allows the device interface orientation to change, pass the new orientation to the AGSLocationDisplay object so that it can appropriately reposition the location symbol.

停止定位

self.mapView.locationDisplay.stopDataSource()

自定义位置符号

SDK提供了三个用于位置符号的默认图像。 这些图像LocationDisplay.png,LocationDisplayCourse.png和LocationDisplayHeading.png包含在ArcGIS.bundle中。

201804169759c.png

根据所使用的Autopan模式以及位置更新提供的信息类型,上图其中一个默认图像将用于位置符号。

在关闭,默认和导航模式下, LocationDisplay.png图像仅在位置信息可用时使用。 LocationDisplayCourse.png用于位置和路线(旅行方向)信息均可用。在关闭和默认模式下,LocationDisplayCourse.png图像会适当地旋转一个由课程指定的数量,以显示设备行进的方向; 但是,在导航模式下,地图会旋转。

Course information 仅在设备以某些非平凡速度移动时才可用。 这就是为什么当设备在车辆中行驶时,地图通常只显示LocationDisplayCourse.png符号。

在 Compass Navigation mode下,LocationDisplayHeading.png图像用于显示设备的位置和方位。

(自定义图像) 您可以通过提供自己的PNG图像来更改位置符号。您的图像必须与默认图像具有相同的名称,并加入Xcode项目中。您的Xcode项目中的图像优先于ArcGIS.bundle中提供的默认图像。在可能的情况下,建议您还为包含视网膜显示的设备添加高分辨率版本的图像。将高分辨率版本命名为LocationDisplay@2x.png,LocationDisplayCourse@2x.png和LocationDisplayHeading@2x.png。

Displaying location information in the callout

Accessing location information 访问位置信息

AGSLocationDisplay provides the device’s location in two ways.

The location property contains the information provided by the underlying data source. The location coordinates will be in a spatial reference chosen by the data source. For example, if the data source is of type AGSCLLocationManagerLocationDisplayDatasource, the coordinates will be in WGS84.

The mapLocation method provides the same location information; however, the coordinates are projected into the map’s spatial reference.

监听位置

AGSLocationDisplay上的location属性是键值观察(KVO)兼容。您可以将观察者附加到此属性以通知位置更新。

func registerAsObserver() {
	self.mapView.locationDisplay.addObserver(self, forKeyPath: "location", options: .New, context: nil)
}
    
override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: [NSObject : AnyObject]!, context: UnsafeMutablePointer<()>) {
	if keyPath == "location" {
         	println("Location updated to \(self.mapView.locationDisplay.mapLocation())")
	}
}

Displaying a callout 显示标注

有时需要显示更多关于地图上显示的功能的信息。例如,用户可能想要看到餐厅的营业时间或房屋的销售价格。这些信息可以使用标注非常有效地显示。

标注将锚定到地图上的地理位置。当用户导航地图时,标注仍保持锚定在相同的位置。标注可以分两部分显示文本:标题和详细信息。该标注还有一个附件按钮( Accessory button )。 此附件按钮可用于显示提供有关该功能的更多信息的另一个视图。 标注还可以在文本的左侧显示40x40像素的图像。

标注是AGSCallout的一个实例。 地图每次只有一个标注,可以通过AGSMapView上的callout属性进行访问。

2018041693792callout.png

自定义标注的外观

您可以更改标注的某些视觉属性,例如其背景颜色,宽度,文本颜色,可见性,附件按钮的外观等。这些元素作为AGSCallout对象的属性公开。

//don't show the accessory button
mapView.callout.accessoryButtonHidden = true
        
//or use a custom image for the accessory button
mapView.callout.accessoryButtonType = .Custom
mapView.callout.accessoryButtonImage = UIImage(named: "<my_image.png>")
        
//Change color of background, title and detail
mapView.callout.color = UIColor.blueColor()
mapView.callout.titleColor = UIColor.redColor()
mapView.callout.detailColor = UIColor.greenColor()

或者,您可以通过设置customView属性来嵌入自己的视图,从而完全更改标注的外观。 下面的示例显示了包含地图,一些按钮和几行文本的标注。

2018041685356callout2.png

点击地图弹出callout

无论用户何时点击地图上的地图项,都会查询标注的delegate是否应为该地图项显示标注。 该delegate不仅控制标注的显示,还可以通过修改AGSCallout对象的属性来自定义标注中显示的信息。

该功能必须属于支持hit-testing的图层。 这些层实现协议AGSHitTestable,例如AGSGraphicsLayer。 如果某个图层不支持点击测试,则该地图无法检测用户是否轻按某个功能,并且通常无法启动该过程以显示该图标的标注。

默认情况下,callout的delegate是未初始化的。这意味着在标注中没有要显示的信息,即使用户点击任何功能,地图也不会显示标注。 要显示标注,您需要将你的其中一个类设置为callout的delegate。 您可以通过让您的类(通常是视图控制器)采用协议并实现协议中定义的一种或多种方法来做到这一点。 在下面的示例中,我们实现了标注:willShowForFeature:layer:mapPoint:方法在标注中显示要素的名称和地址 -

class MyViewController:UIViewController, AGSCalloutDelegate {
 ...   

 func callout(callout: AGSCallout!, willShowForFeature feature: AGSFeature!, layer: AGSLayer!, mapPoint: AGSPoint!) -> Bool {
  //Specify the callout's contents
  mapView.callout.title = feature.attributeAsStringForKey("Name")
  mapView.callout.detail = feature.attributeAsStringForKey("Address")
  mapView.callout.image = UIImage(named: "<my_image.png>") 
  return true
 }
}

请注意,方法实现在最后返回YES。这指示地图继续并显示标注。如果您不想显示某些功能的标注,例如他们缺少地址属性,则可以返回NO。

如果要暂时禁用地图上所有功能的标注,则可以将AGSMapView上的allowCallout属性设置为NO。当你这样做时,只要用户点击时,地图就不再查询标注的委托。

有些时候,您想要根据所显示的功能类型自定义标注中的信息。 为了更轻松地处理这种情况,您可以逐层指定调出代理,而不是集中在调出对象上。 为此,需要将其中一个类设置为图层的calloutDelegate,采用协议并实现标注:willShowForFeature:layer:mapPoint:method

func callout(callout: AGSCallout!, willShowForFeature feature: AGSFeature!, layer: AGSLayer!, mapPoint: AGSPoint!) -> Bool {
	//Specify the callout's contents
...	
	return true
}

Displaying a callout programmatically

Responding to a tap on the callout’s Accessory button

The callout’s delegate is informed by invoking the didClickAccessoryButtonForCallout: method.

func didClickAccessoryButtonForCallout(callout: AGSCallout!) {
	//Handle tap on the accessory button when callout was displayed for a graphic
}

Dismissing a callout

当用户在地图上轻触标注时,标注会自动消失。 if you want to dismiss a callout programatically, you can invoke its dismiss method.

self.mapView.callout.dismiss()

Displaying web map popups