简体   繁体   English

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

[英]How to detect the mapView was moved in Swift and update zoom

I'm trying to set a minimum zoom level on my map in Swift 2. I can't find any documentation on how to restrict a map from being zoomed too far in. What I've decided to try is to monitor for map movement (such as drag or zoom) and then set MKZoomScale back to a minimum.我正在尝试在 Swift 2 中为我的 map 设置最小缩放级别。我找不到任何关于如何限制 map 被放大太多的文档。我决定尝试监视 map 运动(例如拖动或缩放)然后将MKZoomScale设置回最小值。

Most of the answers I've found for regionDidChangeAnimated are in Objective C, which I don't know and I'm having trouble converting them to Swift.我为regionDidChangeAnimated找到的大部分答案都在 Objective C 中,我不知道,我在将它们转换为 Swift 时遇到了麻烦。

I tried implementing @hEADcRASH's answer: https://stackoverflow.com/a/30924768/4106552 , but it doesn't trigger and print anything to the console when the map is moved in the simulator.我尝试实现@hEADcRASH 的答案: https://stackoverflow.com/a/30924768/4106552 ,但当 map 在模拟器中移动时,它不会触发并向控制台打印任何内容。

Can anyone tell me what I'm doing wrong?谁能告诉我我做错了什么? I'm new to Swift, so it could be a small error.我是 Swift 的新手,所以这可能是一个小错误。 Also, let me know if there is a lightweight way to solve for restricting the zoom level on a map. I'm worried that the monitor for movement will slow down the map animation a bit.另外,让我知道是否有一种轻量级的方法可以解决限制 map 上的缩放级别的问题。我担心移动监视器会稍微减慢 map animation 的速度。 Thanks for the help.谢谢您的帮助。

Here is my view controller. import UIKit import Parse import MapKit这是我的观点 controller.import UIKit import Parse import 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")
    }
}
}

After reviewing and combining a number of other questions/answers and the help of @lorenzoliveto I've got it working in Swift. 在回顾并结合了许多其他问题/答案以及@lorenzoliveto的帮助后,我开始在Swift中使用它。 Please leave a comment if there a better/more lightweight way to achieve the same thing. 如果有更好/更轻巧的方法来实现相同目的,请发表评论。

I added self.map.delegate = self to the viewDidLoad function. 我将self.map.delegate = self添加到viewDidLoad函数。

Below is the code for how I'm monitoring for map movement and then once a user has zoomed in "too far" and the width of the map goes below 2 miles I then zoom out the map using mapView.setRegion . 下面是有关我如何监视地图移动的代码,然后,一旦用户将“地图”放大到“太远”并且地图的宽度低于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")
        }
    }

UPDATE: 3/7, I discovered an interesting bug in the implementation above. 更新:3/7,我在上面的实现中发现了一个有趣的错误。 On the simulator it works fine when clicking to zoom, but when you use the pinch to zoom (option + click) the simulator stops allowing you to drag the map around after it animates the zoom back out. 在模拟器上,单击以放大时效果很好,但是当您使用双指进行缩放(选项+单击)时,模拟器将停止,允许您在将缩放动画化后再拖动地图。 This also happened on the beta version on my iphone. 这也发生在我iPhone的Beta版上。 I added dispatch_async around the blocks that animate that map back to their position and it appears to be working on the simulator. 我在将地图动画化回其位置的块周围添加了dispatch_async ,它似乎正在模拟器上运行。 It no longer appears frozen after it animates and I can continue to drag around the map and try to zoom in. 设置动画后,它不再显示为冻结状态,我可以继续在地图上拖动并尝试放大。

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")
})

The solution that works for me is one where I set the zoom range.对我有用的解决方案是我设置缩放范围的解决方案。 This approach may not have been available at the time the question was asked.在提出问题时,此方法可能不可用。 The code fragment below is what I use.下面的代码片段是我使用的。 I'm not entirely sure what the distance units are, but I believe they are meters.我不完全确定距离单位是什么,但我相信它们是米。 Figuring out what range works in a given instance may be a matter of trial and error.弄清楚在给定实例中什么范围有效可能是一个反复试验的问题。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM