检查缩放级别是否更改

发布于 2024-10-06 03:06:00 字数 240 浏览 7 评论 0原文

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

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

帮助?

10倍

I'm using MapKit on iPhone.
How can I know when the user changes the zoom level (zoom in\out the map)?

I've tried to use mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated; but that's called even when the map is only dragged.
Unfortunately, when the map is dragged the mapView.region.span changes as well...

Help?

10x

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

荒人说梦 2024-10-13 03:06:00

计算缩放级别非常简单。请参阅下面的片段。您可以从 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/

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

}

It is pretty simple to calculate the zoom level. See the snippet below. You can get the mRect parameter from the visibleMapRect property on your MKMapView instance.

+ (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;
}

You could probably just stop at the step for calculating the zoomScale as that will tell you if the zoom has changed at all.

I figured this stuff out from reading Troy Brants excellent blog posts on the topic:

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

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

}
牵你手 2024-10-13 03:06:00

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

- (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];
    }
  }
}

I found this very helpful and developed the following code based on these answers.

- (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];
    }
  }
}
南城追梦 2024-10-13 03:06:00

更简单的答案:

获取当前缩放级别的整数的最简单方法是使用 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 是您可以放大地图的最近点以及每个更高的值是一个很远很远的变焦...:-)

Much more simpler answer:

The easiest way to get an Integer of the current zoom level, is by using the MapView function: regionDidChangeAnimated. This function recognizes every change in zoom and will give you the basis for the calculation of the zoom factor.

Just insert this function into your MapView class (works for 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)")
}

And you will get a zoomFactor value out of it, where 0 is the most near point you can zoom into the map and every higher value is a far far away zoom... :-)

天邊彩虹 2024-10-13 03:06:00

我有以下 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];
}

I have the following MKMapView category in which I include a method for quickly getting the current zoom level for the map:

@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

To obtain the zoom level, you can call the following in your delegates and determine if the zoom level has changed:

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    NSUInteger zoomLevel = [mapView zoomLevel];
}
却一份温柔 2024-10-13 03:06:00

您可以收听 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 会因为地球的形状而略有变化,而不是因为用户缩放了。您可能必须检测三角洲的巨大变化并忽略微小的变化

希望有所帮助。

you can listen to the mapView:regionDidChangeAnimated: method. However, this doesn't tell you if the zoom level changed, just if the map was animated.

You will also need to listen to the region property of the map view. This contains the latitudeDelta and the longitudeDelta values which can be used to calculate if the zoom level has changed.

i.e. in the .h file

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

and in your .m file

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

This should detect if the map zoom has changed.

however, you should wach out for the zoom changing because the earth is curved :( If the map is scrolled the latitudeDelta and longitudeDelta will change slightly just because of the shape of the Earth, not because the user has zoomed. You might have to detect a large change in the deltas and ignore slight changes.

Hope that helps.

花海 2024-10-13 03:06:00

在 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
    }
}

Count zoom scale in MKMapView - Swift solution

I created following extension for MKMapView, so you can get a scale of zoom on map. The solution is similar as presented above but in Swift.

There is also additional function scaleWithPrecision(_:Int64) for rounding that scale what allow to filter out f.ex. little zoom changes on 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
    }
}
桜花祭 2024-10-13 03:06:00

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

You could save a latitude delta, then when regionDidChangeAnimated: is called, check to see if the new latitude delta is different. I think the latitude delta stays constant as long as the map isn't zoomed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文