-->

下面针点的N-像素定心的MKMapView(Centering MKMapView on spot

2019-07-21 16:10发布

想中心的MKMapView上的点N像素的给定销低于其可以是或可以不是在当前MapRect可见 )。

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

任何人都已经沿着这条道路( 没有双关语意 )?

Answer 1:

最简单的方法是只要在地图下移,说40%从哪里coordinate会,采取优势span的的region中的MKMapView 。 如果你不需要实际像素,但只需要它向下移动,以便CLLocationCoordinate2D问题是附近的地图(比如10%从顶部的距离)的顶部:

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

如果你想占旋转和摄像头的俯仰,上述技术可能是不够的。 在这种情况下,您可以:

  • 确定您要转移的用户的位置该视图的位置;

  • 将其转换成一个CLLocation ;

  • 计算从该新期望位置的当前用户位置的距离;

  • 从地图上的相机的当前朝向的方向通过该距离移动相机180°。

例如,在斯威夫特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公里米;您使用的是摄像机的角度投迄今所期望的屏幕位置是过去地平线;等等),但实际的,现实世界的场景,像上述可能就足够了。 显然,如果你不要让用户改变相机的间距,答案是更容易。


原来的答复:移动注释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是可见的,然后再开始,所以你可能要到原来的坐标,然后再调整中心。



Answer 2:

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

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

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

看到这里的是: 转换MKCoordinateRegion到MKMapRect

评论:我觉得很奇怪,这是做到这一点的唯一方法,因为MKMapRect是不是一个通常用的MKMapView使用 - 所有的转换方法是MKMapRegion。 但是,好吧,至少它的作品。 经测试,在我自己的项目。



Answer 3:

对于斯威夫特:

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)
}
}


Answer 4:

一个简单的解决方案是,你让你的地图框架查看比可见面积。 然后在地图视图的中心位置的销和隐藏在其他视图或屏幕边界之外的所有不需要的部分。

让我解释。 如果我看看你的屏幕截图,请执行以下操作:

你们之间的距离,销和底部是353像素。 所以,让你的地图视图框高度的两倍:706像素。 你截图具有411像素的高度。 411px = -293像素 - 你的框架在706px的原点位置。 现在,您的中心地图视图在销的协调和你做。

更新4日至2014:

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



Answer 5:

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)
    }


Answer 6:

阅读此线程广告玩弄,尤其是在注释变焦后,我结束了以下程序:

**紧紧围绕注释:**

- (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面板从布局指南覆盖的MapView的两个返回高度



Answer 7:

作为替代接受的答案,我建议你原来的直觉是正确的。 您可以在地图视图中严格工作像素坐标空间来获得偏移和最终定位。 然后使用转换的呼叫从一个位置到屏幕视图,你可以得到最终的位置,并设置地图中心。

这将工作与相机旋转,针对的是屏幕空间。 在我来说,我需要在地图中心,一个引脚上,偏移占地图抽屉里。

下面是转换通话

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

这里是一个快速的4例

//First get the position you want the pin to be (say 1/4 of the way up the screen)
let targetPoint = CGPoint(x: self.frame.width / 2.0, y: self.frame.height * CGFloat(0.25))

//Then get the center of the screen (this is used for calculating the offset as we are using setCenter to move the region
let centerPoint = CGPoint(x: self.frame.width / 2.0, y: self.frame.height / 2.0)

//Get convert the CLLocationCoordinate2D of the pin (or map location) to a screen space CGPoint
let annotationPoint = mapview.convert(myPinCoordinate, toPointTo: mapview)

//And finally do the math to set the offsets in screen space                
let mapViewPointFromAnnotation = CGPoint(x: annotationPoint.x + (centerPoint.x - targetPoint.x), y: annotationPoint.y + (centerPoint.y - targetPoint.y))

//Now convert that result to a Coordinate
let finalLocation = self.convert(mapViewPointFromAnnotation, toCoordinateFrom: mapview)

//And set the map center
mapview.setCenter(finalLocation, animated: true)


Answer 8:

看这个方法MKMapView

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


文章来源: Centering MKMapView on spot N-pixels below pin