mapkit zoom out and then zoom in - swift

I have a zoomed in map. When user picks a new poi I would like to zoom out (animated) and after animation zoom in to the new poi.
However, it's only zooming out, not in. If I use animated:false when zooming out it is working.
How to zoom in when the map is done zoomed out animated?
func centerMapOnLocation(location: CLLocation) {
//Är kartan inzoomad.. zooma ut först.
if isZoomed
{
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
20000, 20000)
OverviewMap.setRegion(coordinateRegion, animated: false)
}
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 4.0, regionRadius * 4.0)
OverviewMap.setRegion(coordinateRegion, animated: true)
isZoomed=true
}

This code should do what you want. didSelectAnnotationView fires when the user taps on a pin.
var zoomingIn = false
var zoomingAnnotation:MKAnnotation
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView)
{
let pin = view as! MKPinAnnotationView
zoomInOnPin(pin.annotation!)
}
func zoomInOnPin(annotation:MKAnnotation) {
let zoomOutRegion = MKCoordinateRegion(center: mapView.region.center, span: MKCoordinateSpan(latitudeDelta: 0.09, longitudeDelta: 0.09))
zoomingIn = true
zoomingAnnotation = annotation
mapView.setRegion(zoomOutRegion, animated: true)
}
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if let annotation = zoomingAnnotation where zoomingIn == true {
zoomingIn = false
let region = MKCoordinateRegion(center: zoomingAnnotation.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.07, longitudeDelta: 0.07))
mapView.setRegion(region, animated: true)
}
}

You need to make sure one setRegion animation has completed prior to calling the next setRegion.
look into the MKmapViewDelegate regionDidChangeAnimated method. This will allow you to react to the completion of the setRegion animated and chain the next setRegion animation.

Related

How to set a default altitude for MKMapView if MKMapCamera:fromDistance is being ignored?

struct MapViewExample: UIViewRepresentable {
let location = CLLocation()
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.showsUserLocation = true
mapView.userTrackingMode = .followWithHeading
let camera = MKMapCamera(
lookingAtCenter: location.coordinate,
fromDistance: 100,
pitch: 0,
heading: location.course
)
mapView.setCamera(camera, animated: true)
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
print(uiView.camera.altitude)
}
}
This example creates a MKMapView that shows the user's location, follows the user's heading, and sets a default camera altitude of 100. The altitude value is then logged to the console every time the view updates.
Console output always starts with the right value, but then it gets overridden:
100.0
100.0
3613.103143079447
3613.103143079447
3613.103143079447
3613.103143079447

move to MKPointAnnotation old let long to new let long with animation

how can in a `enter code here map-kit move to MKPointAnnotation old let long to new let long with animation with move Move With Effect in swift
used this code
animation with also draw a polyline
let startPosition = CLLocationCoordinate2D(latitude: 23.0118, longitude: 72.5055)
let destinationPosition = CLLocationCoordinate2D(latitude: 23.0133, longitude: 72.5308)
// Set the region the MapView will be looking at at.
let region = MKCoordinateRegionMakeWithDistance(startPosition, 100000, 100000)
mapView.setRegion(region, animated: true)
moveDelivery(CLLocationCoordinate2D(latitude: 23.0133, longitude: 72.5308))
allLocations.append(startPosition)
// Add annotation to map.
myAnnotation.coordinate = startPosition
mapView.addAnnotation(myAnnotation)
` weak var timer: Timer?
func movePosition() {
// Set timer to run after 5 seconds.
timer = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { [self] _ in
// Set animation to last 4 seconds.
UIView.animate(withDuration: 10, animations: { // Update annotation coordinate to be the destination coordinate
self.myAnnotation.coordinate = destinationPosition
}, completion: nil)
}
}
// Start moving annotation.
movePosition()
`
used than MKPointAnnotation Move but I cant draw Polyline parallel in swift

MapKit Error: NSHostingView is being laid out reentrantly while rendering its SwiftUI content

I have implemented a slightly changed version of the Apple SwiftUI tutorial using MapKit.
When I run it I get the error message and resize the corresponding view I get:
[SwiftUI] NSHostingView is being laid out reentrantly while rendering its SwiftUI content. This is not supported and the current layout pass will be skipped.
View calling code:
MapView(coordinate: location?.coordinates)
.frame(minHeight: 200)
.overlay(
GeometryReader{
proxy in
Button("Open in Maps") {
if (self.location?.coordinates != nil){
let destination = MKMapItem(placemark: MKPlacemark(coordinate: self.location!.coordinates))
destination.name = "the car"
destination.openInMaps()
}
}
.frame(width: proxy.size.width, height: proxy.size.height, alignment: .bottomTrailing)
.offset(x: -10, y: -10)
}
)
MapView struct:
import SwiftUI
import MapKit
/// a view containing the map
struct MapView: NSViewRepresentable {
/// the location coordinates
var coordinate: CLLocationCoordinate2D?
func makeNSView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateNSView(_ nsView: MKMapView, context: Context) {
let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
var region: MKCoordinateRegion = MKCoordinateRegion()
if (self.coordinate != nil){
region = MKCoordinateRegion(center: coordinate!, span: span)
}
nsView.setRegion(region, animated: true)
if ((nsView.annotations.count == 0) && (self.coordinate != nil)){
let locationPin: MKPointAnnotation = MKPointAnnotation()
locationPin.coordinate = coordinate!
nsView.addAnnotations([locationPin])
}
}
}
Got the same message and desperately tried first dispatch in main.sync but got exceptions at runtime.
Then I simply tried async.
{
let region = MKCoordinateRegion(center: visibleArea.coordinate,
latitudinalMeters: 200, longitudinalMeters: 200)
DispatchQueue.main.async
{
nsView.setRegion(region, animated: false)
}
}
works also with animation
DispatchQueue.main.async
{
nsView.setRegion(region, animated: true)
}
Actually that did the trick for now: it remove
the violet information message in Xcode (12.3)
remove the console message
Hope that is only a little patch until Apple clean it up (or explain why).

How to draw custom shapes on MKMapView

I need to draw custom shapes like Arc, Semi-circle? I tried the below code but it's not rendering anything on the MKMapView.
Is this the right way to draw custom shapes?
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
mapView.delegate = self
let center = CLLocationCoordinate2D(latitude: 15.463157486154865, longitude: 73.78846049308775)
let radius = CLLocationCoordinate2D(latitude: 15.495608080208948, longitude: 73.83418584279791)
addCircle(center: center, radius: radius)
}
private func createArcPath() -> UIBezierPath {
let center = CLLocationCoordinate2D(latitude: 15.463157486154865, longitude: 73.78846049308775)
// converting the coordinates to CGPoint with respect to MKMapView.
let centerPoint = mapView.convert(center, toPointTo: self.mapView)
// Creating bezierPath of arc.
let path = UIBezierPath(arcCenter: centerPoint, radius: 6080.205481929489, startAngle: CGFloat.pi, endAngle: CGFloat.pi * 2, clockwise: true)
return path
}
}
extension ViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKCircle {
let arcRenderer = MKOverlayPathRenderer()
arcRenderer.path = createArcPath().cgPath
arcRenderer.strokeColor = UIColor.red
arcRenderer.fillColor = UIColor.red
arcRenderer.lineWidth = 10
arcRenderer.alpha = 1
arcRenderer.lineCap = .round
return arcRenderer
}
return MKOverlayRenderer()
}
}
extension ViewController {
private func addCircle(center ccoordinate: CLLocationCoordinate2D, radius rcoordinate: CLLocationCoordinate2D) {
let centerLocation = CLLocation.init(latitude: ccoordinate.latitude, longitude: ccoordinate.longitude)
let radiusLocation = CLLocation.init(latitude: rcoordinate.latitude, longitude: rcoordinate.longitude)
let radius = centerLocation.distance(from: radiusLocation)
let circle = MKCircle(center: ccoordinate, radius: radius)
mapView.addOverlay(circle)
}
}
Use this to add custom shape in MAPVIEW
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
{
if overlay is MKCircle
{
print("overlay latitude: "+String(overlay.coordinate.latitude))
print("overlay longitude: "+String(overlay.coordinate.longitude))
let circleOverlay = overlay as! MKCircle
if(circleOverlay.accessibilityPath != nil)
{
let arcRenderer = MKOverlayPathRenderer()
arcRenderer.path = circleOverlay.accessibilityPath?.cgPath
arcRenderer.strokeColor = UIColor.red
arcRenderer.lineWidth = 10
arcRenderer.alpha = 0.3
return arcRenderer
}
let circle = MKCircleRenderer(overlay: overlay)
circle.strokeColor = UIColor.black
circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
circle.lineWidth = 1
circle.alpha = 0.3
return circle
}
}
After some RND I came across a library curvyRoute & used it to draw arch on MKMapView.
// Adds arch overlay to the mapView
private func addArcOverlays() {
let pointA = CLLocationCoordinate2D(latitude: 15.463157486154865, longitude: 73.78846049308775)
let pointB = CLLocationCoordinate2D(latitude: 15.495608080208948, longitude: 73.83418584279791)
mapView.addOverlay(LineOverlay(origin: pointA, destination: pointB))
let style = LineOverlayStyle(strokeColor: .red, lineWidth: 4, alpha: 1)
let arc = ArcOverlay(origin: pointA, destination: pointB, style: style)
arc.radiusMultiplier = 0.5
mapView.addOverlay(arc)
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
switch overlay {
case let lineOverlay as LineOverlay:
let linerender = MapLineOverlayRenderer(lineOverlay)
setVisibleMapRect(linerender.overlay, animated: true)
return linerender
case let polyline as MKPolyline:
let renderer = MKPolylineRenderer(overlay: polyline)
renderer.strokeColor = UIColor.yellow.withAlphaComponent(0.5)
renderer.lineWidth = 4
return renderer
default:
return MKOverlayRenderer()
}
}

MKMapView (MapKit) - Trying to zoom out to see the entire globe

Edit: I found a solution. MKMapView won't show the entire globe if you build it in Xcode's simulator, but it will if you build it on an actual device.
Existing versions of the question haven't worked - Need Swift 4, Xcode 10 solution:
I'm trying to zoom an MKMapView out to show the entire globe in my app. I can zoom out to see a map of the whole world, but not the entire globe.
​
Here's what I know:
-It has to be satellite, hybrid, satelliteFlyover, or hybridFlyover
-3D must be enabled.
​
Here is what I've tried:
-Adjusting the span of the region (no matter how big I make the span, it never zooms out enough to see the globe)
-Adjusting the altitude of the camera (no matter how high I make it, it never zooms out enough to see the globe)
​
I have googled and stack-overflowed, and I can't find any solutions that work. I am reduced to posting this question myself, violating my lurker principals, but I am totally stuck.
Here is some code I've tried from tutorials, etc. (several attempts commented out):
import UIKit
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
mapView.mapType = .standard
mapView.isPitchEnabled = true
// mapView.showsBuildings = true // displays buildings
let eiffelTowerCoordinates = CLLocationCoordinate2DMake(48.85815, 2.29452)
mapView.region = MKCoordinateRegion(center: eiffelTowerCoordinates, latitudinalMeters: 1000, longitudinalMeters: 100) // sets the visible region of the map
// create a 3D Camera
let mapCamera = MKMapCamera()
mapCamera.centerCoordinate = eiffelTowerCoordinates
mapCamera.pitch = 45
mapCamera.altitude = 50000000 // example altitude
mapCamera.heading = 45
// set the camera property
mapView.camera = mapCamera
// var ausCenter = CLLocationCoordinate2D(latitude: -25.354917, longitude: 134.347407)
// let camera = MKMapCamera(lookingAtCenter: ausCenter, fromDistance: 300, pitch: 10, heading: 0)
// mapView.camera = camera
// var ausCenter = CLLocationCoordinate2D(latitude: -25.354917, longitude: 134.347407)
// var ausSpan = MKCoordinateSpan(latitudeDelta: 5, longitudeDelta: 5)
// var region = MKCoordinateRegion(center: ausCenter, span: ausSpan)
// mapView.setRegion(region, animated: true)
// let camera = MKMapCamera()
// camera.centerCoordinate = mapView.centerCoordinate
// camera.pitch = 90.0
// camera.altitude = 30000000
// camera.heading = 0
// mapView.setCamera(camera, animated: true)
// var ausCenter = CLLocationCoordinate2D(latitude: -25.354917, longitude: 134.347407)
//
//// mapView.setCenter(ausCenter, animated: true)
//
// let span = MKCoordinateSpan(latitudeDelta: 150, longitudeDelta: 150)
// let region = MKCoordinateRegion(center: ausCenter, span: span)
// mapView.setRegion(region, animated: true)
//
// //add an annotation
// let annotation = MKPointAnnotation()
// annotation.coordinate = ausCenter
// annotation.title = "Australia"
// annotation.subtitle = "Details Forthcoming"
// mapView.addAnnotation(annotation)
}
}