将MKMapView置于引脚下方的N点像素上

时间:2013-03-14 22:06:09

标签: ios objective-c mapkit core-location

想要将MKMapView置于给定引脚下方的N个像素当前MapRect 中可能显示或可能不显示)的位置。

我一直试图用-(CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(UIView *)view的各种剧本来解决这个问题但没有成功。

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

enter image description here

8 个答案:

答案 0 :(得分:78)

最简单的方法是将地图向下移动,比如说coordinate所在位置的40%,利用span的{​​{1}} region }。如果您不需要实际的像素,只需要向下移动,以便所讨论的MKMapView靠近地图的顶部(比如距离顶部10%):

CLLocationCoordinate2D

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

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

  • 将其转换为CLLocationCoordinate2D center = coordinate; center.latitude -= self.mapView.region.span.latitudeDelta * 0.40; [self.mapView setCenterCoordinate:center animated:YES]; ;

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

  • 将相机移动距离地图相机当前标题180°的方向。

E.g。在Swift 3中,类似于:

CLLocation

其中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

因此,即使相机倾斜并且在正北方向以外的方向上,这也会移动用户的位置(位于下方十字准线的中心位置)高达150像素(上方十字线所在的位置),产生类似于:

enter image description here

显然,你应该意识到堕落的情况(例如你距离南极1公里,你试图将地图向上移动2公里;你使用的摄像机角度到目前为止所需的屏幕位置已经超越了地平线;等等,但对于实际的,现实世界的场景,像上面这样的东西可能就足够了。显然,如果你不让用户改变相机的音高,答案就更容易了。


原始答案:用于移动注释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 } } 像素

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

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]; 可见时才有效,因此您可能必须先转到原始坐标,然后调整中心。

答案 1 :(得分:7)

可靠地执行此操作的唯一方法是使用以下内容:

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

为了在您想要居中的地图区域的情况下执行此操作,您必须将地图区域转换为MKMapRect。显然,使用边缘填充作为像素偏移。

在此处查看: Convert MKCoordinateRegion to MKMapRect

评论:我发现这是唯一的方法,因为MKMapRect不是通常用于MKMapView的东西,所以这是唯一的方法 - 所有转换方法都适用于MKMapRegion。但是,好吧,至少它有效。在我自己的项目中测试过。

答案 2 :(得分:3)

对于Swift:

import MapKit

extension MKMapView {

func moveCenterByOffSet(offSet: CGPoint, coordinate: CLLocationCoordinate2D) {
    var point = self.convert(coordinate, toPointTo: self)

    point.x += offSet.x
    point.y += offSet.y

    let center = self.convert(point, toCoordinateFrom: self)
    self.setCenter(center, animated: true)
}

func centerCoordinateByOffSet(offSet: CGPoint) -> CLLocationCoordinate2D {
    var point = self.center

    point.x += offSet.x
    point.y += offSet.y

    return self.convert(point, toCoordinateFrom: self)
}
}

答案 3 :(得分:2)

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

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

您的针脚与底部之间的距离为353像素。因此,使地图视图框架的高度为两倍:706像素。截图的高度为411像素。将帧定位在706px - 411px = -293像素的原点。 现在将地图视图置于引脚坐标的中心,您就完成了。

2014年3月4日更新:

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

答案 4 :(得分:1)

SWIFT 3更新

使用缩放

更新了功能
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)
    }

答案 5 :(得分:0)

在阅读了这个线程广告后,特别是在缩放注释时,我最终得到了以下程序:

**以注释为中心:**

- (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都会从布局指南中返回覆盖地图视图的面板高度

答案 6 :(得分:0)

作为公认答案的替代方法,我建议您最初的直觉是正确的。您可以严格在地图视图像素坐标空间内工作,以获得偏移量和最终定位。然后,使用从位置到屏幕视图的转换调用,您可以获取最终位置并设置地图中心。

这将在相机旋转且相对于屏幕空间的情况下起作用。在我的情况下,我需要将地图居中放置在大头针上,并有一个偏移量以说明地图抽屉。

以下是转化调用

SELECT * FROM Grades WHERE Grades.StudentID = 12

这是一个迅速的4个例子

func convert(_ coordinate: CLLocationCoordinate2D, toPointTo view: UIView?) -> CGPoint
func convert(_ point: CGPoint, toCoordinateFrom view: UIView?) -> CLLocationCoordinate2D

答案 7 :(得分:-6)

MKMapView上查看此方法:

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