MKMapView 边界?

发布于 2024-08-18 08:29:49 字数 130 浏览 4 评论 0原文

任何人都知道在 MKMapView 上实现边界的简单方法。例如,我想告诉地图它只能停留在一个区域。我希望用户能够滚动,但当他们到达某个纬度/经度时让他们停止。我尝试使用 willChangeRegion: delegate 但这把我搞砸了。谢谢。

Anyone know of an easy way to implement boundaries on an MKMapView. For example, I want to tell the map it can only stay in one area. I want to user to be able to scroll but have them stop when they get to a certain latitude/longitude. I tried using the willChangeRegion: delegate but that screwed me over. Thanks.

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

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

发布评论

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

评论(3

煞人兵器 2024-08-25 08:29:49

我刚刚写了一篇关于此的博客文章,请在此处查看:http://blog.jamgraham.com/blog/2012/04/29/adding-boundaries-to-mkmapview/

我从事的一个项目需要锁定 MKMapView 的边界。由于苹果没有提供开箱即用的解决方案,我们只能对 MKMapView 进行子类化。这非常简单,您可以访问地图中的 UIScrollView 以及 MKMapView 中的其他有趣对象。

现在想查看代码吗?它可以在这里找到: https://github.com/jamgraham/geoFencer

锁定 MKMapView 调用的边界两个一般步骤。首先是将缩放级别锁定为最小和最大。其次是防止用户滚动到您创建的铸造厂之外。让我们通过查看需要覆盖的委托来逐步了解这些内容

1. 缩放级别

这非常简单。目标是在用户缩放时检查缩放级别,并在用户停止缩放时再次检查缩放级别。

 -(void)scrollViewDidZoom:(UIScrollView *)scrollView;
 -(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;

2. 滚动边界

这有点复杂。当用户在 UIScrollView 中滚动地图时,我们要确保它们不会超出边界,如果超出边界,我们要阻止它们。当我们看到用户超出边界时,我们可以通过将地图重新​​定位到边界来实现这一点。这种情况发生得足够快,用户感觉自己撞到了墙上,而不是地图在晃动。以下是我们需要注意的代表:

 -(void)scrollViewDidScroll:(UIScrollView *)scrollView;
 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

3. 复制和复制粘贴

请随意复制并粘贴下面的自定义 MKMapView。在显示地图的 UIViewController 中,自定义地图视图需要设置边界

ViewController.m

    //Set map boundaries
    mapView.showsUserLocation = YES;
    [mapViewsetZoomMax:0.015551];
    [mapViewsetZoomMin: 0.346360];
    mapView.top = 37.773498;
    mapView.bottom = 37.745130;
    mapView.left = -122.430365;
    mapView.right = -122.401623;

GeoMapView.h

@interface GeoMapView : MKMapView
{
    MKCoordinateRegion cordRegion;
    CLLocationCoordinate2D oldcenter;
    double left;
    double right;
    double top;
    double bottom;
    double zoomMax;
    double zoomMin;
}

-(void)checkZoom;
-(void)checkScroll;

@property (nonatomic) double left;
@property (nonatomic) double right;
@property (nonatomic) double top;
@property (nonatomic) double bottom;
@property (nonatomic) double zoomMax;
@property (nonatomic) double zoomMin;

@end

GeoMapView.m

#import "GeoMapView.h"

@implementation GeoMapView
@synthesize  left, right, top, bottom,zoomMax,zoomMin;

- (id)initWithFrame:(CGRect)frame
{
    self = [superinitWithFrame:frame];
    if (self) {

    }
    returnself;
}

-(void)scrollViewDidZoom:(UIScrollView *)scrollView {
    [selfcheckZoom];    
}


-(void)checkZoom{
    UIScrollView * scroll = [[[[selfsubviews] objectAtIndex:0] subviews] objectAtIndex:0];

    if (scroll.zoomScale < zoomMax) {
        NSLog(@"Reached Max Zoom");
        [scroll setZoomScale:zoomMaxanimated:NO];
    }

    if (scroll.zoomScale >= zoomMin) {
        NSLog(@"Reached Min Zoom");
        [scroll setZoomScale:zoomMinanimated:NO];

    }
}

-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    UIScrollView * scroll = [[[[selfsubviews] objectAtIndex:0] subviews] objectAtIndex:0];

    if (scroll.zoomScale > zoomMin) {
        [scroll setZoomScale:zoomMinanimated:NO];
    }   
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

    [selfcheckScroll];

}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    [selfcheckScroll];
}

-(void)checkScroll{
    @try{
        cordRegion = self.region;

        CLLocationCoordinate2D center = self.region.center;
        CLLocationCoordinate2D northWestCorner, southEastCorner;
        northWestCorner.latitude  = center.latitude  + (self.region.span.latitudeDelta  / 2.0);
        northWestCorner.longitude = center.longitude - (self.region.span.longitudeDelta / 2.0);
        southEastCorner.latitude  = center.latitude  - (self.region.span.latitudeDelta  / 2.0);
        southEastCorner.longitude = center.longitude + (self.region.span.longitudeDelta / 2.0);

        CLLocationCoordinate2D newcenter;
        newcenter.latitude = self.region.center.latitude;
        newcenter.longitude = self.region.center.longitude;

        //LEFT
        CLLocationDegrees farLeft = left;
        CLLocationDegrees snapToLeft = farLeft + (self.region.span.longitudeDelta  / 2.0);
        if (northWestCorner.longitude < farLeft)
        {
            newcenter.longitude = snapToLeft;
            cordRegion = self.region;
        }

        //RIGHT
        CLLocationDegrees r = (self.region.span.longitudeDelta / 2.0);
        CLLocationDegrees farRight = right;
        CLLocationDegrees snapToRight = farRight - r;
        if (southEastCorner.longitude > farRight)
        {
            newcenter.longitude = snapToRight;
        }

        //TOP
        CLLocationDegrees farTop = top;
        CLLocationDegrees snapToTop = top - (self.region.span.latitudeDelta  / 2.0);
        if (northWestCorner.latitude > farTop)
        {
            newcenter.latitude = snapToTop;
        }

        //BOTTOM
        CLLocationDegrees farBottom = bottom;
        CLLocationDegrees rr = (self.region.span.latitudeDelta  / 2.0);
        CLLocationDegrees snapToBottom = bottom + rr;
        if (southEastCorner.latitude < farBottom)
        {            
            newcenter.latitude = snapToBottom;
        }

        [selfsetCenterCoordinate:newcenter  animated:NO];

    }
    @catch (NSException *e) {
    }
    @finally {}
}


@end

想法

现在,地理围栏领域正在发生很多很酷的事情。一些想法:

  • 输入地址并将地图锁定到该地址
  • 使用地图叠加进行地理围栏
  • 物理游戏,当用户实际访问这些物理位置时解锁地图区域。

I just wrote a blog post about this, check it out here: http://blog.jamgraham.com/blog/2012/04/29/adding-boundaries-to-mkmapview/

I worked on a project with a requirement to lock the boundaries of MKMapView. As there is no out-of-the-box solution provided by apple we are left subclassing MKMapView. This is pretty easy and gives you access to the UIScrollView that lives in the map and other fun objects in the MKMapView.

Want to look at the code now? It's available here: https://github.com/jamgraham/geoFencer

Locking the boundaries of the a MKMapView invokes two general steps. First is to lock the zoom level to a min and max. Second is to prevent the user from scrolling outside the foundry you create. Lets walk through these by looking at the delegates we need to override

1. Zoom Level

This is pretty straight forward. The goal is the check the zoom level as the user zooms and again when the user stops zooming.

 -(void)scrollViewDidZoom:(UIScrollView *)scrollView;
 -(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;

2. Scrolling boundaries

This is a bit more complex. As the user scrolls around the map in the UIScrollView we want to make sure they do not go outside the boundaries and if they do we want to stop them. We can achieve this by repositioning the map to the boundary when we see the user go outside the boundary. This happens fast enough where the users feels like they've hit a wall rather than the map jerking around. Here are the delegates we need to watch for:

 -(void)scrollViewDidScroll:(UIScrollView *)scrollView;
 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

3. Copy & Paste

Feel free to copy and paste the custom MKMapView below. In the UIViewController that show the map the custom map view needs the boundaries set

ViewController.m

    //Set map boundaries
    mapView.showsUserLocation = YES;
    [mapViewsetZoomMax:0.015551];
    [mapViewsetZoomMin: 0.346360];
    mapView.top = 37.773498;
    mapView.bottom = 37.745130;
    mapView.left = -122.430365;
    mapView.right = -122.401623;

GeoMapView.h

@interface GeoMapView : MKMapView
{
    MKCoordinateRegion cordRegion;
    CLLocationCoordinate2D oldcenter;
    double left;
    double right;
    double top;
    double bottom;
    double zoomMax;
    double zoomMin;
}

-(void)checkZoom;
-(void)checkScroll;

@property (nonatomic) double left;
@property (nonatomic) double right;
@property (nonatomic) double top;
@property (nonatomic) double bottom;
@property (nonatomic) double zoomMax;
@property (nonatomic) double zoomMin;

@end

GeoMapView.m

#import "GeoMapView.h"

@implementation GeoMapView
@synthesize  left, right, top, bottom,zoomMax,zoomMin;

- (id)initWithFrame:(CGRect)frame
{
    self = [superinitWithFrame:frame];
    if (self) {

    }
    returnself;
}

-(void)scrollViewDidZoom:(UIScrollView *)scrollView {
    [selfcheckZoom];    
}


-(void)checkZoom{
    UIScrollView * scroll = [[[[selfsubviews] objectAtIndex:0] subviews] objectAtIndex:0];

    if (scroll.zoomScale < zoomMax) {
        NSLog(@"Reached Max Zoom");
        [scroll setZoomScale:zoomMaxanimated:NO];
    }

    if (scroll.zoomScale >= zoomMin) {
        NSLog(@"Reached Min Zoom");
        [scroll setZoomScale:zoomMinanimated:NO];

    }
}

-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
    UIScrollView * scroll = [[[[selfsubviews] objectAtIndex:0] subviews] objectAtIndex:0];

    if (scroll.zoomScale > zoomMin) {
        [scroll setZoomScale:zoomMinanimated:NO];
    }   
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

    [selfcheckScroll];

}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    [selfcheckScroll];
}

-(void)checkScroll{
    @try{
        cordRegion = self.region;

        CLLocationCoordinate2D center = self.region.center;
        CLLocationCoordinate2D northWestCorner, southEastCorner;
        northWestCorner.latitude  = center.latitude  + (self.region.span.latitudeDelta  / 2.0);
        northWestCorner.longitude = center.longitude - (self.region.span.longitudeDelta / 2.0);
        southEastCorner.latitude  = center.latitude  - (self.region.span.latitudeDelta  / 2.0);
        southEastCorner.longitude = center.longitude + (self.region.span.longitudeDelta / 2.0);

        CLLocationCoordinate2D newcenter;
        newcenter.latitude = self.region.center.latitude;
        newcenter.longitude = self.region.center.longitude;

        //LEFT
        CLLocationDegrees farLeft = left;
        CLLocationDegrees snapToLeft = farLeft + (self.region.span.longitudeDelta  / 2.0);
        if (northWestCorner.longitude < farLeft)
        {
            newcenter.longitude = snapToLeft;
            cordRegion = self.region;
        }

        //RIGHT
        CLLocationDegrees r = (self.region.span.longitudeDelta / 2.0);
        CLLocationDegrees farRight = right;
        CLLocationDegrees snapToRight = farRight - r;
        if (southEastCorner.longitude > farRight)
        {
            newcenter.longitude = snapToRight;
        }

        //TOP
        CLLocationDegrees farTop = top;
        CLLocationDegrees snapToTop = top - (self.region.span.latitudeDelta  / 2.0);
        if (northWestCorner.latitude > farTop)
        {
            newcenter.latitude = snapToTop;
        }

        //BOTTOM
        CLLocationDegrees farBottom = bottom;
        CLLocationDegrees rr = (self.region.span.latitudeDelta  / 2.0);
        CLLocationDegrees snapToBottom = bottom + rr;
        if (southEastCorner.latitude < farBottom)
        {            
            newcenter.latitude = snapToBottom;
        }

        [selfsetCenterCoordinate:newcenter  animated:NO];

    }
    @catch (NSException *e) {
    }
    @finally {}
}


@end

Ideas

There's a lot of cool stuff going on in geofencing right now. Some ideas:

  • Enter an address and lock the map to that address
  • Geofencing with map overlays
  • Physical games that unlock areas of the map as the user actually visits those physical places.
半山落雨半山空 2024-08-25 08:29:49

因此,我将继续回答我自己的问题,并说不,没有简单的方法来实现这种行为。您不仅必须检查边界,还必须检查滚动的方向,控制台不断告诉我:滚动后最后一次触摸,但未调用scrollViewDidEndDragging:willDecelerate:!我想我还有很多研究要做......

So I am going to go ahead and answer my own question and say no there is no EASY way to implement this behavior. Not only do you have to check the boundaries, but you also have to check the direction of the scrolling, and the console keeps telling me: last touch after scroll but scrollViewDidEndDragging:willDecelerate: wasn't called! I guess I have so more research to do...

匿名。 2024-08-25 08:29:49

我一直在做一些研究,发现没有简单的方法可以做到这一点。

所以我的解决方案是让地图锁定在某个区域,并让包含MKMapView的scrollView进行放大和缩小。

I have been doing some research and found out there is no easy way of doing it.

So my solution is to have the map locked in a certain area, and have the scrollView which contains the MKMapView to zoom in and out.

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