将MKMapView集中在引脚下方的N像素点上

希望将MKMapView居中放置在给定引脚下的N像素点( 在当前MapRect中可能不可见 )。

我一直试图解决这个使用各种戏剧-(CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view没有成功。

任何人都在这条路上( 没有双关语 )?

在这里输入图像说明

最简单的方法就是将地图向下移动,比如coordinate位置的40%,利用MKMapView regionspan 。 如果您不需要实际的像素,只需要将其向下移动,以使相关的CLLocationCoordinate2D靠近地图的顶部(比如离顶部10%):

 CLLocationCoordinate2D center = coordinate; center.latitude -= self.mapView.region.span.latitudeDelta * 0.40; [self.mapView setCenterCoordinate:center animated:YES]; 

如果你想考虑相机的旋转和俯仰,上面的技术可能是不够的。 在这种情况下,您可以:

  • 确定您想要移动用户位置的视图中的位置;

  • 将其转换为CLLocation ;

  • 计算当前用户位置距新的所需位置的距离;

  • 将摄像机移动距离地图摄像机当前方向180°的方向。

例如在Swift 3中,就像是:

 var point = mapView.convert(mapView.centerCoordinate, toPointTo: view) point.y -= offset let coordinate = mapView.convert(point, toCoordinateFrom: view) let offsetLocation = coordinate.location let distance = mapView.centerCoordinate.location.distance(from: offsetLocation) / 1000.0 let camera = mapView.camera let adjustedCenter = mapView.centerCoordinate.adjust(by: distance, at: camera.heading - 180.0) camera.centerCoordinate = adjustedCenter 

其中CLLocationCoordinate2D具有以下extension

 extension CLLocationCoordinate2D { var location: CLLocation { return CLLocation(latitude: latitude, longitude: longitude) } private func radians(from degrees: CLLocationDegrees) -> Double { return degrees * .pi / 180.0 } private func degrees(from radians: Double) -> CLLocationDegrees { return radians * 180.0 / .pi } func adjust(by distance: CLLocationDistance, at bearing: CLLocationDegrees) -> CLLocationCoordinate2D { let distanceRadians = distance / 6_371.0 // 6,371 = Earth's radius in km let bearingRadians = radians(from: bearing) let fromLatRadians = radians(from: latitude) let fromLonRadians = radians(from: longitude) let toLatRadians = asin( sin(fromLatRadians) * cos(distanceRadians) + cos(fromLatRadians) * sin(distanceRadians) * cos(bearingRadians) ) var toLonRadians = fromLonRadians + atan2(sin(bearingRadians) * sin(distanceRadians) * cos(fromLatRadians), cos(distanceRadians) - sin(fromLatRadians) * sin(toLatRadians)) // adjust toLonRadians to be in the range -180 to +180... toLonRadians = fmod((toLonRadians + 3.0 * .pi), (2.0 * .pi)) - .pi let result = CLLocationCoordinate2D(latitude: degrees(from: toLatRadians), longitude: degrees(from: toLonRadians)) return result } } 

因此,即使摄像机倾斜,并且在正北以外的方向上,也会将用户的位置(其中下十字线位于中心)上移150像素(上方的十字线所在的位置),产生如下所示的结果:

在这里输入图像说明

显然,你应该意识到退化的情况(例如,你离南极1公里,你试图将地图向上移动2公里;你正在使用一个摄像机angular度,以至于所需的屏幕位置已经超过了地平线等),但是对于实际的,真实的情况,类似上述的东西可能就足够了。 显然,如果不让用户改变摄像机的音调,答案就更简单了。


原始答案:用于移动注释n像素

如果您有CLLocationCoordinate2D ,则可以将其转换为CGPoint ,将其移动x个像素,然后将其转换回CLLocationCoordinate2D

 - (void)moveCenterByOffset:(CGPoint)offset from:(CLLocationCoordinate2D)coordinate { CGPoint point = [self.mapView convertCoordinate:coordinate toPointToView:self.mapView]; point.x += offset.x; point.y += offset.y; CLLocationCoordinate2D center = [self.mapView convertPoint:point toCoordinateFromView:self.mapView]; [self.mapView setCenterCoordinate:center animated:YES]; } 

你可以通过以下方式调用它

 [self moveCenterByOffset:CGPointMake(0, 100) from:coordinate]; 

不幸的是,这只有在开始之前coordinate是可见的,所以你可能必须先到原来的坐标,然后调整中心。

可靠地做到这一点的唯一方法是使用以下内容:

 - (void)setVisibleMapRect:(MKMapRect)mapRect edgePadding:(UIEdgeInsets)insets animated:(BOOL)animate 

为了做到这一点,给定一个地图区域,你要中心,你必须将地图区域转换为MKMapRect。 很明显,使用边缘填充的像素偏移量。

看到这里: 将MKCoordinateRegion转换为MKMapRect

评论:我觉得这很奇怪,只有这样才能做到这一点,因为MKMapRect并不是一个通常用于MKMapView的东西 – 所有的转换方法都是针对MKMapRegion的。 但是,好吧,至less它是有效的。 在我自己的项目中testing。

一个简单的解决scheme是,您使地图视图的框架大于可见区域。 然后将您的图钉放置在地图视图的中心,并将所有不需要的区域隐藏在另一个视图或屏幕边界之外。

让我详细说一下。 如果我查看您的屏幕截图,请执行以下操作:

你的针脚和底部之间的距离是353像素。 因此,使您的地图视图框架高度的两倍:706像素。 你截图的高度是411像素。 将您的框架放置在706px – 411px = -293像素的原点处。 现在将你的地图视图置于图钉的坐标上,就完成了。

更新4 – 2014年3月:

我用Xcode 5.0.2创build了一个小的示例应用程序来演示这个: http : //cl.ly/0e2v0u3G2q1d

对于Swift:

 import MapKit extension MKMapView { func moveCenterByOffSet(offSet: CGPoint, coordinate: CLLocationCoordinate2D) { var point = self.convertCoordinate(coordinate, toPointToView: self) point.x += offSet.x point.y += offSet.y let center = self.convertPoint(point, toCoordinateFromView: self) self.setCenterCoordinate(center, animated: true) } func centerCoordinateByOffSet(offSet: CGPoint) -> CLLocationCoordinate2D { var point = self.center point.x += offSet.x point.y += offSet.y return self.convertPoint(point, toCoordinateFromView: self) } } 

SWIFT 3已更新

使用缩放更新了该function

 func zoomToPos() { let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) // Create a new MKMapRegion with the new span, using the center we want. let coordinate = moveCenterByOffset(offset: CGPoint(x: 0, y: 100), coordinate: (officeDetail?.coordinate)!) let region = MKCoordinateRegion(center: coordinate, span: span) mapView.setRegion(region, animated: true) } func moveCenterByOffset (offset: CGPoint, coordinate: CLLocationCoordinate2D) -> CLLocationCoordinate2D { var point = self.mapView.convert(coordinate, toPointTo: self.mapView) point.x += offset.x point.y += offset.y return self.mapView.convert(point, toCoordinateFrom: self.mapView) } 

看了这个线程广告后,特别是在放大注释的时候,我结束了以下过程:

**以注释为中心:**

 - (void) centerOnSelection:(id<MKAnnotation>)annotation { MKCoordinateRegion region = self.mapView.region; region.center = annotation.coordinate; CGFloat per = ([self sizeOfBottom] - [self sizeOfTop]) / (2 * self.mapView.frame.size.height); region.center.latitude -= self.mapView.region.span.latitudeDelta * per; [self.mapView setRegion:region animated:YES]; } 

**放大注释:**

 - (void) zoomAndCenterOnSelection:(id<MKAnnotation>)annotation { DLog(@"zoomAndCenterOnSelection"); MKCoordinateRegion region = self.mapView.region; MKCoordinateSpan span = MKCoordinateSpanMake(0.005, 0.005); region.center = annotation.coordinate; CGFloat per = ([self sizeOfBottom] - [self sizeOfTop]) / (2 * self.mapView.frame.size.height); region.center.latitude -= self.mapView.region.span.latitudeDelta * span.latitudeDelta / region.span.latitudeDelta * per; region.span = span; [self.mapView setRegion:region animated:YES]; } 

-(CGFloat) sizeOfBottom-(CGFloat) sizeOfTop都从布局指南返回覆盖地图视图的面板高度

看看MKMapView上的这个方法:

 - (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated