Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The easiest technique is to just shift the map down, say 40% from where the <code>coordinate</code> would be, taking advantage of the <code>span</code> of the <code>region</code> of the <code>MKMapView</code>. If you don't need actual pixels, but just need it to move down so that the <code>CLLocationCoordinate2D</code> in question is near the top of the map (say 10% away from the top):</p> <pre><code>CLLocationCoordinate2D center = coordinate; center.latitude -= self.mapView.region.span.latitudeDelta * 0.40; [self.mapView setCenterCoordinate:center animated:YES]; </code></pre> <hr> <p>If you want to account for rotation and pitch of the camera, the above technique may not be adequate. In that case, you could:</p> <ul> <li><p>Identify the position in the view to which you want to shift the user location;</p></li> <li><p>Convert that to a <code>CLLocation</code>;</p></li> <li><p>Calculate the distance of the current user location from that new desired location;</p></li> <li><p>Move the camera by that distance in the direction 180&deg; from the current heading of the map's camera.</p></li> </ul> <p>E.g. in Swift 3, something like:</p> <pre><code>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 </code></pre> <p>Where <code>CLLocationCoordinate2D</code> has the following <code>extension</code>:</p> <pre><code>extension CLLocationCoordinate2D { var location: CLLocation { return CLLocation(latitude: latitude, longitude: longitude) } private func radians(from degrees: CLLocationDegrees) -&gt; Double { return degrees * .pi / 180.0 } private func degrees(from radians: Double) -&gt; CLLocationDegrees { return radians * 180.0 / .pi } func adjust(by distance: CLLocationDistance, at bearing: CLLocationDegrees) -&gt; 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 } } </code></pre> <p>So, even with the camera pitched and at a heading other than due north, this moves the user's location (which is centered, where the lower crosshair is) up 150 pixels (where the upper crosshair is), yielding something like:</p> <p><a href="https://i.stack.imgur.com/IpttQ.gif" rel="noreferrer"><img src="https://i.stack.imgur.com/IpttQ.gif" alt="enter image description here"></a></p> <p>Obviously, you should be conscious about degenerate situations (e.g. you're 1 km from the south pole and you try to shift the map up 2 km meters; you're using a camera angle pitched so far that the desired screen location is past the horizon; etc.), but for practical, real-world scenarios, something like the above might be sufficient. Obviously, if you don't let the user change the pitch of the camera, the answer is even easier.</p> <hr> <p><strong>Original answer: for moving the annotation <code>n</code> pixels</strong></p> <p>If you have a <code>CLLocationCoordinate2D</code>, you can convert it to a <code>CGPoint</code>, move it x pixels, and then convert it back to a <code>CLLocationCoordinate2D</code>:</p> <pre><code>- (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]; } </code></pre> <p>You can call this by:</p> <pre><code>[self moveCenterByOffset:CGPointMake(0, 100) from:coordinate]; </code></pre> <p>Unfortunately, this only works if the <code>coordinate</code> is visible before you start, so you might have to go to the original coordinate first, and then adjust the center.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload