如何检测在Swift中移动的mapView并更新缩放



我正在Swift 2中尝试在地图上设置最小缩放级别。我找不到任何关于如何限制地图放大过远的文档。我决定尝试监视地图的移动(如拖动或缩放),然后将MKZoomScale设置回最小值。

我为regionDidChangeAnimated找到的大多数答案都在Objective C中,我不知道,而且我很难将它们转换为Swift。

我试着实现@hEADcRASH的答案:https://stackoverflow.com/a/30924768/4106552,但当地图在模拟器中移动时,它不会触发并将任何内容打印到控制台。

有人能告诉我我做错了什么吗?我是斯威夫特的新手,所以这可能是一个小错误。此外,请告诉我是否有一种轻量级的方法可以解决限制地图缩放级别的问题。我担心运动监视器会使地图动画的速度减慢一点。谢谢你的帮助。

这是我的视图控制器。导入UIKit导入分析导入MapKit

class SearchRadiusViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
@IBOutlet weak var map: MKMapView!
@IBOutlet weak var menuBtn: UIBarButtonItem!
var locationManager = CLLocationManager()
override func viewDidLoad() {
    super.viewDidLoad()
    //menu button control
    if self.revealViewController() != nil {
        menuBtn.target = self.revealViewController()
        menuBtn.action = "revealToggle:"
        self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
    }
    //user location
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    locationManager.startUpdatingLocation()

}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    //set map
    let location:CLLocationCoordinate2D = manager.location!.coordinate
    let latitude = location.latitude
    let longitude = location.longitude
    let latDelta:CLLocationDegrees = 0.1
    let longDelta:CLLocationDegrees = 0.1
    let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
    let maplocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
    let region:MKCoordinateRegion = MKCoordinateRegionMake(maplocation, span)
    map.setRegion(region, animated: true)
    //stop updating location, only need user location once to position map.
    manager.stopUpdatingLocation()
}
//Attempt to monitor for map movement based on hEADcRASH's answer.
private var mapChangedFromUserInteraction = false
private func mapViewRegionDidChangeFromUserInteraction() -> Bool {
    let view = self.map.subviews[0]
    //  Look through gesture recognizers to determine whether this region change is from user interaction
    if let gestureRecognizers = view.gestureRecognizers {
        for recognizer in gestureRecognizers {
            if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) {
                return true
            }
        }
    }
    return false
}
func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
    print("yes")
    mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction()
    if (mapChangedFromUserInteraction) {
        // user changed map region
        print("user changed map in WILL")
    }
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
            print("yes ddd")
    if (mapChangedFromUserInteraction) {
        // user changed map region
        print("user changed map in Did")
    }
}
}

在回顾并结合了许多其他问题/答案以及@lorenzolivette的帮助后,我已经在Swift中使用了它。如果有更好/更轻量级的方法可以实现同样的效果,请留下评论。

我在viewDidLoad函数中添加了self.map.delegate = self

以下是我如何监控地图移动的代码,一旦用户放大"太远",地图宽度低于2英里,我就会使用mapView.setRegion缩小地图。

private var mapChangedFromUserInteraction = false
private func mapViewRegionDidChangeFromUserInteraction() -> Bool {
    let view = self.map.subviews[0]
    //  Look through gesture recognizers to determine whether this region change is from user interaction
    if let gestureRecognizers = view.gestureRecognizers {
        for recognizer in gestureRecognizers {
            if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) {
                return true
            }
        }
    }
    return false
}
func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
    mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction()
    if (mapChangedFromUserInteraction) {
        // user will change map region
        print("user WILL change map.")
        // calculate the width of the map in miles.
        let mRect: MKMapRect = mapView.visibleMapRect
        let eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect))
        let westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect))
        let currentDistWideInMeters = MKMetersBetweenMapPoints(eastMapPoint, westMapPoint)
        let milesWide = currentDistWideInMeters / 1609.34  // number of meters in a mile
        print(milesWide)
        print("^miles wide")
        // check if user zoomed in too far and zoom them out.
        if milesWide < 2.0 {
            var region:MKCoordinateRegion = mapView.region
            var span:MKCoordinateSpan = mapView.region.span
            span.latitudeDelta = 0.04
            span.longitudeDelta = 0.04
            region.span = span;
            mapView.setRegion(region, animated: true)
            print("map zoomed back out")
        }
    }
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    if (mapChangedFromUserInteraction) {
        // user changed map region
        print("user CHANGED map.")
        print(mapView.region.span.latitudeDelta)
        print(mapView.region.span.longitudeDelta)
        // calculate the width of the map in miles.
        let mRect: MKMapRect = mapView.visibleMapRect
        let eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect))
        let westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect))
        let currentDistWideInMeters = MKMetersBetweenMapPoints(eastMapPoint, westMapPoint)
        let milesWide = currentDistWideInMeters / 1609.34  // number of meters in a mile
        print(milesWide)
        print("^miles wide")
        // check if user zoomed in too far and zoom them out.
        if milesWide < 2.0 {
            var region:MKCoordinateRegion = mapView.region
            var span:MKCoordinateSpan = mapView.region.span
            span.latitudeDelta = 0.04
            span.longitudeDelta = 0.04
            region.span = span;
            mapView.setRegion(region, animated: true)
            print("map zoomed back out")
        }
    }

更新:3/7,我在上面的实现中发现了一个有趣的bug。在模拟器上,单击进行缩放时效果良好,但当您使用捏缩进行缩放(选项+单击)时,模拟器将停止允许您在设置缩小动画后拖动地图。这也发生在我的iphone测试版上。我在将贴图动画化回其位置的块周围添加了dispatch_async,它似乎正在模拟器上工作。它在动画化后不再显示冻结,我可以继续在地图上拖动并尝试放大。

dispatch_async(dispatch_get_main_queue(), {
   var region:MKCoordinateRegion = mapView.region
   var span:MKCoordinateSpan = mapView.region.span
   span.latitudeDelta = 0.04
   span.longitudeDelta = 0.04
   region.span = span;
   mapView.setRegion(region, animated: true)
   print("map zoomed back out")
})

适合我的解决方案是设置缩放范围。在提出问题时,可能还没有这种方法。下面的代码片段就是我使用的。我不完全确定距离单位是多少,但我相信它们是米。弄清楚在给定的例子中什么范围有效可能是一个反复试验的问题。

        let mapView = MKMapView(frame: .zero)        
        let zoomRange = MKMapView.CameraZoomRange(
            minCenterCoordinateDistance: 120000,
            maxCenterCoordinateDistance: 1600000
        )
        mapView.cameraZoomRange = zoomRange

最新更新