【问题标题】:Swift - Making MapView callout annotation visible when pin annotation clicked by UserSwift - 当用户单击引脚注释时,使 MapView 标注注释可见
【发布时间】:2017-02-22 18:37:38
【问题描述】:
请观察链接的图片(底部,下方)
当用户将地图屏幕移动到图钉最终靠近屏幕边缘的位置,然后选择该图钉注释时,Apple 方法随后将地图屏幕稍微移向屏幕中心,以便图钉注释标注可见。
我的问题有两个:
我。调用什么 Apple 方法来进行屏幕调整?
二。如果实现了 MKMapViewDelegate 扩展,那么在 mapView didSelect 视图方法中实现相同功能的最聪明的方法是什么?
Mapview屏幕调整顺序:
【问题讨论】:
标签:
ios
swift
mkmapview
mapkit
mkmapviewdelegate
【解决方案1】:
理论上,你可以获取annotation view的frame并检查它是否离map view的边缘太近:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
// if view.frame is too close to the edges of the MKMapView, triggered your desired method
}
实际上这是不可靠的,因为它还取决于注释视图的标注气泡。我们需要根据标注气泡的大小为“太靠近边缘”标准设置一个不同的阈值,对此没有简单的方法。
这有点hacky:当屏幕调整时,regionWillChangeAnimated 方法会被调用。如果它在点击注释的瞬间触发,则很有可能是由用户点击注释引起的:
weak var tappedAnnotationView: MKAnnotationView?
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
self.tappedAnnotationView = view // this property will only be non-nil for 0.1 seconds
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
self.tappedAnnotationView = nil
}
}
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
if self.tappedAnnotationView != nil {
print("map adjusted due to tap on an annotation view")
}
}
它适用于我对其进行的基本测试,但由于它是一个 hack,因此显然会出现极端情况。
【解决方案2】:
我想出的是以下内容:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
// Get Coordinate for Selected Map Pin
let selectedPinCoordinate = (view.annotation?.coordinate)!
// Determine (X,Y) coordinates for Selected Map Pin on view (mapView)
let SelectedPinMapPoint = mapView.convert(selectedPinCoordinate, toPointTo: mapView)
// Determine (X,Y) coordinate for center point of view (mapView)
let mapCenterMapPoint = mapView.convert(mapView.centerCoordinate, toPointTo: mapView)
// Define an inner view within the existing view frame. Any Selected Map Pin outside
// bounds of inner view is deemed to be too close to the edge of the map for the callout
// to be fully viewable by the user
let innerRectFrameMinX = mapView.frame.maxX * 0.15
let innerRectFrameMaxX = mapView.frame.maxX * 0.85
let innerRectFrameMinY = mapView.frame.maxY * 0.30
let innerRectFrameMaxY = mapView.frame.maxY * 0.85
// Create a variable which will serve as the new center (X,Y) coordinate
var newCenter = CGPoint()
// Default new center (X,Y) coordinate to current view (X,Y) coordinate
newCenter.x = mapCenterMapPoint.x
newCenter.y = mapCenterMapPoint.y
// Determine if x coordinate of Selected Map Pin is outside bounds. If so,
// set a new center x coordinate so callout can be clearly seen by the user
switch (SelectedPinMapPoint.x) {
case _ where (SelectedPinMapPoint.x < innerRectFrameMinX):
newCenter.x = mapView.frame.midX - (innerRectFrameMinX - SelectedPinMapPoint.x)
case _ where (SelectedPinMapPoint.x > innerRectFrameMaxX):
newCenter.x = mapView.frame.midX + (SelectedPinMapPoint.x - innerRectFrameMaxX)
default: break
}
// Determine if y coordinate of Selected Map Pin is outside bounds. If so,
// set a new center y coordinate so callout can be clearly seen by the user
switch (SelectedPinMapPoint.y) {
case _ where (SelectedPinMapPoint.y < innerRectFrameMinY):
newCenter.y = mapView.frame.midY - (innerRectFrameMinY - SelectedPinMapPoint.y)
case _ where (SelectedPinMapPoint.y > innerRectFrameMaxY):
newCenter.y = mapView.frame.midY + (SelectedPinMapPoint.y - innerRectFrameMaxY)
default: break
}
// Convert new map Center (X,Y) coordinate to map coordinate
let newCenterCoordinate = mapView.convert(newCenter, toCoordinateFrom: nil)
// Set new center as center for map view
mapView.setCenter(newCenterCoordinate, animated: true)
}
我已经链接了我的概念的粗略图形草图,无论它可能提供什么好处。Rough Graphical Sketch