【问题标题】:Check whether zoom level changed检查缩放级别是否改变
【发布时间】:2011-05-20 13:17:50
【问题描述】:

我在 iPhone 上使用 MapKit。 我如何知道用户何时更改缩放级别(放大/缩小地图)?

我尝试使用 ma​​pView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated; 但即使仅拖动地图也会调用它。 不幸的是,当地图被拖动时,mapView.region.span 也会发生变化......

帮助?

10 倍

【问题讨论】:

    标签: iphone objective-c iphone-sdk-3.0 mapkit mkmapview


    【解决方案1】:

    计算缩放级别非常简单。请参阅下面的 sn-p。您可以从 MKMapView 实例的 visibleMapRect 属性中获取 mRect 参数。

    + (NSUInteger)zoomLevelForMapRect:(MKMapRect)mRect withMapViewSizeInPixels:(CGSize)viewSizeInPixels
    {
        NSUInteger zoomLevel = MAXIMUM_ZOOM; // MAXIMUM_ZOOM is 20 with MapKit
        MKZoomScale zoomScale = mRect.size.width / viewSizeInPixels.width; //MKZoomScale is just a CGFloat typedef
        double zoomExponent = log2(zoomScale);
        zoomLevel = (NSUInteger)(MAXIMUM_ZOOM - ceil(zoomExponent));
        return zoomLevel;
    }
    

    您可能只需要在计算zoomScale 的步骤处停下来,因为这会告诉您缩放是否发生了变化。

    我通过阅读 Troy Brants 关于该主题的优秀博客文章了解了这些内容:

    http://troybrant.net/blog/2010/01/mkmapview-and-zoom-levels-a-visual-guide/

    斯威夫特 3

    extension MKMapView {
    
        var zoomLevel: Int {
            let maxZoom: Double = 20
            let zoomScale = self.visibleMapRect.size.width / Double(self.frame.size.width)
            let zoomExponent = log2(zoomScale)
            return Int(maxZoom - ceil(zoomExponent))
        }
    
    }
    

    【讨论】:

    • 哇!这看起来正是我需要的。锐化一点 - 我从哪里获得 viewSizeInPixels?
    • viewSizeInPixels 是 MKMapView 实例的 bounds.size 属性
    • 很有帮助,需要确定地图是否放大到最大。谢谢。
    • 如果不是很明显,您可以从 MKMapView 实例的visibleMapRect 属性中获取mapRect
    • 我尝试使用您的代码,但发现了一些奇怪的东西。我做了一些调试,现在我很困惑。 MKZoomScale zoomScale 给我返回 4727 之类的东西,但是当我放大 - (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale 时,它大约是 0.000488...。我哪里错了?
    【解决方案2】:

    我发现这很有帮助,并根据这些答案开发了以下代码。

    - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated 
    {
       mapRegion = self.mapView.region;
    }
    
    
    -(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
    
    MKCoordinateRegion newRegion = self.mapView.region;
    
    NSInteger zFactor;
    if ((mapRegion.span.latitudeDelta/newRegion.span.latitudeDelta) > 1.5){
        NSLog(@"Zoom in changed");
        zFactor = 20;
        CustomPlacemark *aO; 
        MKAnnotationView *aV; 
        for (aO in self.mapView.annotations) {
            aV = [[self mapView] viewForAnnotation:aO];
            aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y, aV.frame.size.width+zFactor, aV.frame.size.height+zFactor);
            [[[self mapView] viewForAnnotation:aO] setFrame:aV.frame];
        }
    }
    if ((mapRegion.span.latitudeDelta/newRegion.span.latitudeDelta) < 0.75){
        NSLog(@"Zoom out");
        zFactor = -20;
        CustomPlacemark *aO; 
        MKAnnotationView *aV; 
        for (aO in self.mapView.annotations) {
            aV = [[self mapView] viewForAnnotation:aO];
            aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y, aV.frame.size.width+zFactor, aV.frame.size.height+zFactor);
            [[[self mapView] viewForAnnotation:aO] setFrame:aV.frame];
        }
      }
    }
    

    【讨论】:

    【解决方案3】:

    我有以下 MKMapView 类别,其中包含一种快速获取地图当前缩放级别的方法:

    @implementation MKMapView (ZoomLevel)
    
    - (NSUInteger) zoomLevel {
        MKCoordinateRegion region = self.region;
    
        double centerPixelX = [MKMapView longitudeToPixelSpaceX: region.center.longitude];
        double topLeftPixelX = [MKMapView longitudeToPixelSpaceX: region.center.longitude - region.span.longitudeDelta / 2];
    
        double scaledMapWidth = (centerPixelX - topLeftPixelX) * 2;
        CGSize mapSizeInPixels = self.bounds.size;
        double zoomScale = scaledMapWidth / mapSizeInPixels.width;
        double zoomExponent = log(zoomScale) / log(2);
        double zoomLevel = 21 - zoomExponent;
    
        return zoomLevel;
    }
    
    @end
    

    要获取缩放级别,您可以在您的代理中调用以下命令并确定缩放级别是否已更改:

    - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
        NSUInteger zoomLevel = [mapView zoomLevel];
    }
    

    【讨论】:

    • 这很好,除了 -longitudeToPixelSpaceX: 是一个很大的未知数。
    • MKMapRect visibleRect = self.visibleMapRect;双 centerPixelX = visibleRect.origin.x+visibleRect.size.width/2; double topLeftPixelX = visibleRect.origin.x;
    • 我最近在自己的应用程序中简化了这个,效果很好,更简洁gist.github.com/4178336
    【解决方案4】:

    更简单的答案:

    获取当前缩放级别的整数的最简单方法是使用 MapView 函数:regionDidChangeAnimated。此功能可识别缩放的每一次变化,并为您提供计算缩放系数的基础。

    只需将此函数插入​​您的 MapView 类(适用于 Swift 3.0):

    var mapView: MKMapView! = nil
    
    ...
    
    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
        let zoomWidth = mapView.visibleMapRect.size.width
        let zoomFactor = Int(log2(zoomWidth)) - 9
        print("...REGION DID CHANGE: ZOOM FACTOR \(zoomFactor)")
    }
    

    你会从中得到一个 zoomFactor 值,其中 0 是你可以放大地图的最近点,每个更高的值是一个很远的缩放... :-)

    【讨论】:

    • 是的,只要地图实际发生变化,也就是我关心缩放时,就会调用它。谢谢!
    【解决方案5】:

    您可以收听mapView:regionDidChangeAnimated: 方法。但是,这并不能告诉您缩放级别是否发生了变化,只是地图是动画的。

    您还需要收听地图视图的region 属性。这包含 latitudeDelta 和 longitudeDelta 值,可用于计算缩放级别是否已更改。

    即在 .h 文件中

    @class MyMapViewController {
        ...
        MKCoordinateRegion mapRegion;
        }
    @end
    

    在你的 .m 文件中

    - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
        mapRegion = mapView.region;
    }
    
    - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
        newRegion = mapView.region;
    
        if (mapRegion.span.latitudeDelta != newRegion.span.latitudeDelta ||
            mapRegion.span.longitudeDelta != newRegion.span.longitudeDelta)
            NSLog(@"The zoom has changed");
    }
    

    这应该检测地图缩放是否已更改。

    但是,您应该注意缩放变化,因为地球是弯曲的 :( 如果滚动地图,latitudeDelta 和 longitudeDelta 会因为地球的形状而略有变化,而不是因为用户已经缩放。您可能必须检测增量中的大变化并忽略微小的变化。

    希望对您有所帮助。

    【讨论】:

    • 比我的答案更完整。我认为当你走向两极时,经度三角洲会发生变化,但无论你走到哪里,纬度三角洲都会保持不变。可能需要一些测试来检查它是否足够稳定以供使用。
    • 我永远不记得哪些变化和哪些没有变化所以我刚刚在我的答案中测试了这两个:) 我想你可以测试看看他们是否会改变它必须是用户缩放,如果只有一个变化它是一个卷轴?
    • 伙计们,我希望您能在发布之前稍微检查一下您的“解决方案”。你的想法都不行。跨度增量确实发生了变化 - 并且变化很大。
    • 5 分钟测试告诉我 latitudeDelta 一直在变化,longitudeDelta 只有在您缩放时才会改变,所以如果您只测试 longitudeDelta,我的答案将有效。我们不是来为您解决问题的,我们是来帮助您自己找到解决方案的,我认为我们做到了。
    • 没问题,tbh,我应该回答它未经测试:)
    【解决方案6】:

    在 MKMapView 中计算缩放比例 - Swift 解决方案

    我为 MKMapView 创建了以下扩展,因此您可以在地图上进行缩放。解决方案与上面介绍的类似,但在 Swift 中。

    还有一个附加函数 scaleWithPrecision(_:Int64) 用于舍入该比例以过滤掉 f.ex。 MapView 上的缩放变化很小

    extension MKMapView {
    
        var scale: Double {
    
            return self.scaleWithPrecision(1)
        }
    
        func scaleWithPrecision(precision: Int64) -> Double {
    
            let mapBoundsWidth = Double(self.bounds.size.width)
            let mapRectWidth:Double = self.visibleMapRect.size.width
    
            let scale: Double = round(Double(precision)*mapBoundsWidth/mapRectWidth)/Double(precision)
    
            return scale
        }
    }
    

    【讨论】:

      【解决方案7】:

      您可以保存一个纬度增量,然后在调用regionDidChangeAnimated: 时,检查新的纬度增量是否不同。我认为只要地图没有缩放,纬度增量就会保持不变。

      【讨论】:

      • 好吧,你错了。拖动地图时,跨度值会发生变化。
      猜你喜欢
      • 2018-11-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-22
      • 1970-01-01
      • 2016-03-26
      • 1970-01-01
      • 2015-03-25
      • 1970-01-01
      相关资源
      最近更新 更多