iOS - 如何将MapView限制到特定区域?
我有以下问题:
我有一个“绘制的地图”(图像),我将其作为叠加层添加到 MapView 中。没问题..但我需要将 MapView 限制在覆盖区域,因此用户无法在该区域之外滚动/缩放..但应该可以在“边界”内滚动/缩放覆盖层的“ - 意味着我不能只禁用 MapView 的缩放/滚动。
关于这个主题有什么想法/解决方案吗?使用MapView/-Kit的原因是我需要向自定义地图添加各种POI。当仅使用 ImageView+ScrollView 来呈现自定义地图时,这可能会变得更加复杂。
我对这个主题进行了大量研究,但没有找到很好的解决方案。
任何帮助表示赞赏!
此致, Christian
编辑:这是我们的解决方案: 您提供左上角和右下角坐标来限制地图。 (最小)缩放级别也受到限制。我已经停用了减速,您可以从地图上弹起一点(以获得更好的性能/用户体验)。我在叠加层中添加了约 1 公里的灰色边框,这样用户就无法看到 google 的原始世界地图。
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:
#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
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.
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.
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.
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:
#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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在尝试了有限 MKMapView 的不同方法之后,我得出的结论是,使用 mapDidChange 并在中心点超出边界时进行重置效果最好,并带有动画:是的,
这是我的做法(使用新西兰纬度/长跨度/中心)。
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
Here's how I do it (Using the New Zealand lat/Long span/center).
通过实现:
-(void) mapView:(MKMapView *)mapView RegionWillChangeAnimated:(BOOL)animated
您应该能够将区域重置为您的特定区域。
查看该答案以了解如何操作的示例来做到这一点。
另一种解决方案可以带来更精确的事件,但更复杂(我目前正在成功地将其用于另一个需求)是子类
MKMapView
并覆盖UIScrollViewDelegate
协议。如果您这样做,请确保像这样调用
super
实现:注意:虽然协议是公共的,但
MKMapView
实现未知,并且可能与 iOS 版本不同,所以之前检查一下respondsToSelector:
会更安全。您必须调用超级实现,否则 Map 将无法正常工作。By implementing :
-(void) mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
You should be able to reset region to your specific one.
Look at that answer to 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 overrideUIScrollViewDelegate
protocol.If you do that, make sure to call
super
implementation like that :Note: While the protocol is public,
MKMapView
implementation is unknown and might differ with iOS versions, so it is more safe to check withrespondsToSelector:
before. You must call super implementations or Map will just not work properly.我知道这是一个相当老的问题,但为了避免无限循环,你可以尝试这样的事情: https://stackoverflow.com/ a/4126011/1234011
基本上设置一个标志,以防止回调再次触发(如果是您设置了该值)。
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
Basically set a flag to prevent the callback from firing again if it was you who set the value.