iOS - 如何将 MapView 限制到特定区域?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5680896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS - How to limit the MapView to a specific region?
提问by cweinberger
I have the following problem:
我有以下问题:
I have a "drawn map" (image) which I add to the MapView as an Overlay. No Problem with that.. but I need to limit the MapView to the region of the Overlay, so a user isn't able to scroll/zoom outside of this region.. but it should be possible to scroll/zoom inside the "bounds" of the overlay - means I cannot just disable zoom/scrolling for the MapView.
我有一个“绘制的地图”(图像),我将其作为叠加添加到 MapView。没问题..但我需要将 MapView 限制在覆盖的区域内,因此用户无法在该区域外滚动/缩放.. 但应该可以在“边界”内滚动/缩放" 的叠加层 - 意味着我不能只是禁用 MapView 的缩放/滚动。
Are there any ideas/solution on this topic? The reason for using the MapView/-Kit is that I need to add various POIs to the custom map. This may become more complex when just using an ImageView+ScrollView for presenting the custom map.
关于这个话题有什么想法/解决方案吗?使用 MapView/-Kit 的原因是我需要在自定义地图中添加各种 POI。当仅使用 ImageView+ScrollView 来呈现自定义地图时,这可能会变得更加复杂。
I've researched alot on this topic, but I didn't found a nice solution.
我已经对这个主题进行了大量研究,但没有找到一个很好的解决方案。
Any help is appreciated!
任何帮助表示赞赏!
Best Regards, Christian
最好的问候,克里斯蒂安
Edit: This is our solution:You supply a topleft and a bottomright coordinate to limit the map. The (minimum) zoomlevel is also limited. I've deactivated decelerating and you are able to bounce a bit out of the map (for better performance/ux). I added a ~1km grey border to the overlay so the user isn?t able to see the orignal worldmap of google.
编辑:这是我们的解决方案:您提供左上角和右下角坐标来限制地图。(最小)缩放级别也受到限制。我已经停用了减速功能,您可以从地图中稍微弹跳一下(以获得更好的性能/用户体验)。我在叠加层中添加了一个约 1 公里的灰色边框,因此用户无法看到 google 的原始世界地图。
LimitedMapView.h:
LimitedMapView.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface LimitedMapView : MKMapView <UIScrollViewDelegate>{
}
@property (nonatomic, assign) CLLocationCoordinate2D topLeftCoordinate;
@property (nonatomic, assign) CLLocationCoordinate2D bottomRightCoordinate;
@end
LimitedMapView.m:
LimitedMapView.m:
#import "LimitedMapView.h"
@implementation LimitedMapView
@synthesize topLeftCoordinate, bottomRightCoordinate;
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
if([super respondsToSelector:@selector(scrollViewDidZoom:)]) [super scrollViewDidZoom:scrollView];
if ([self region].span.latitudeDelta > 0.002401f || [self region].span.longitudeDelta > 0.003433f) {
CLLocationCoordinate2D center = self.centerCoordinate;
MKCoordinateSpan span = MKCoordinateSpanMake(0.002401f, 0.003433f);
self.region = MKCoordinateRegionMake(center, span);
}
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if([super respondsToSelector:@selector(scrollViewDidEndDragging:)]) [super scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
MKCoordinateRegion currentRegion = self.region;
bool changeRegionLong = YES;
bool changeRegionLat = YES;
// LONGITUDE
if((currentRegion.center.longitude - (currentRegion.span.longitudeDelta/2)) < self.topLeftCoordinate.longitude) {
currentRegion.center.longitude = (topLeftCoordinate.longitude + (currentRegion.span.longitudeDelta/2));
} else if((currentRegion.center.longitude + (currentRegion.span.longitudeDelta/2)) > self.bottomRightCoordinate.longitude) {
currentRegion.center.longitude = (bottomRightCoordinate.longitude - (currentRegion.span.longitudeDelta/2));
} else {
changeRegionLong = NO;
}
// LATITUDE
if((currentRegion.center.latitude + (currentRegion.span.latitudeDelta/2)) > self.topLeftCoordinate.latitude) {
currentRegion.center.latitude = (topLeftCoordinate.latitude - (currentRegion.span.latitudeDelta/2));
} else if((currentRegion.center.latitude - (currentRegion.span.latitudeDelta/2)) < self.bottomRightCoordinate.latitude) {
currentRegion.center.latitude = (bottomRightCoordinate.latitude + (currentRegion.span.latitudeDelta/2));
} else {
changeRegionLat = NO;
}
if(changeRegionLong || changeRegionLat) [self setRegion:currentRegion animated:YES];
}
-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
[scrollView setContentOffset:scrollView.contentOffset animated:YES];
}
@end
采纳答案by Vincent Guerci
By implementing :
通过实施:
-(void) mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
-(void) mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
You should be able to reset region to your specific one.
您应该能够将区域重置为您的特定区域。
Look at that answerto have an example of how to do this.
看在这个问题的答案有一个如何做到这一点的例子。
Another solution, that brings more precise events but is more complex(I'm currently using this successfully for another need)is to subclass MKMapView
and override UIScrollViewDelegate
protocol.
另一个带来更精确事件但更复杂的解决方案(我目前正在成功地将它用于另一个需求)是子类化MKMapView
和覆盖UIScrollViewDelegate
协议。
If you do that, make sure to call super
implementation like that :
如果这样做,请确保super
像这样调用实现:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if ([super respondsToSelector:@selector(scrollViewWillBeginDragging:)])
[super scrollViewWillBeginDragging:scrollView];
// do what you want
}
Note: While the protocol is public, MKMapView
implementation is unknown and might differ with iOS versions, so it is more safe to check with respondsToSelector:
before. You mustcall super implementations or Map will just not work properly.
注意:虽然协议是公开的,但MKMapView
实现未知,并且可能因 iOS 版本而异,因此respondsToSelector:
之前检查更安全。您必须调用超级实现,否则 Map 将无法正常工作。
回答by David van Dugteren
After trying different ways of limited MKMapView I've concluded that using mapDidChange, and resetting if you're center point goes outside of the boundaries works best, with animated: YES
在尝试了限制 MKMapView 的不同方法后,我得出结论,使用 mapDidChange,如果中心点超出边界,则重置效果最好,动画效果:是
Here's how I do it (Using the New Zealand lat/Long span/center).
这是我的做法(使用新西兰纬度/长跨度/中心)。
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
if ((mapView.region.span.latitudeDelta > 15.589921 ) || (mapView.region.span.longitudeDelta > 175.836914) ) {
CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914);
MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 );
MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ);
[mapView setRegion: NZRegion animated: YES];
}
if (abs(abs(mapView.region.center.latitude) - 41.162114) > (13.589921 / 2) ) {
CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914);
MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 );
MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ);
[mapView setRegion: NZRegion animated: YES];
}
if (abs(abs(mapView.region.center.longitude) - 172.836914) > (14.062500 / 2) ) {
CLLocationCoordinate2D centerCoord = CLLocationCoordinate2DMake(-41.162114, 172.836914);
MKCoordinateSpan spanOfNZ = MKCoordinateSpanMake(13.589921, 14.062500 );
MKCoordinateRegion NZRegion = MKCoordinateRegionMake(centerCoord, spanOfNZ);
[mapView setRegion: NZRegion animated: YES];
}
}
回答by Ken Koch
I know this is a pretty old question, but to avoid the infinite loop you could try something like this: https://stackoverflow.com/a/4126011/1234011
我知道这是一个很老的问题,但为了避免无限循环,你可以尝试这样的事情:https: //stackoverflow.com/a/4126011/1234011
Basically set a flag to prevent the callback from firing again if it was you who set the value.
如果是您设置了值,则基本上设置一个标志以防止回调再次触发。
- Ken
- 肯