New SwiftUI Assist for MapKit in Xcode 15


At WWDC 2023, Apple introduced higher SwiftUI help for MapKit. MapKit is a large API, so it’ll be some time earlier than we see a completely native SwiftUI model. But it surely’s undoubtedly getting simpler to show an interactive map view in your app. Probably the most widely-used characteristic — annotations — will get a giant enchancment, and the brand new map model modifier requires nearly no work so as to add a ton of pizzazz to your app. Slowly however certainly, MapKit is buying a extra SwiftUI “contact and really feel”.

On the draw back, in case you’ve written a whole lot of Map code up to now couple of years, you would possibly have to rewrite a few of it, as Xcode 15 replaces all of the Xcode 12 Map initializers.

Getting Began

Click on Obtain supplies on the high or backside of this text to obtain the starter venture. Open it in Xcode 15 beta to see what you must work with.

PublicArt

I wrote the primary model of PublicArt in 2014 for my very first raywenderlich.com tutorial MapKit Tutorial: Getting Began. It was an replace of Ray’s authentic MapKit tutorial, and Andrew Tetlaw up to date it once more in 2020.

In 2019, I tailored PublicArt for SwiftUI Tutorial: Navigation. Utilizing Xcode 11, I needed to create a struct MapView: UIViewRepresentable to show an MKMapView in a SwiftUI app.

Earlier this yr, Josh Steele up to date PublicArt to Xcode 14.2 for our SwiftUI Fundamentals course. That is the starter venture for this text: It makes use of the SwiftUI Map launched in Xcode 12.

For this text, the starter venture has iOS Deployment set to iOS 17.

Xcode 12 Map

Open LocationMap within the code editor. There’s an MKCoordinateRegion @State property. You go a binding to this into the Map initializer, together with an array of annotationItems, then show a MapMarker utilizing an art work merchandise’s coordinate property. When the Map view seems, you set area.middle and area.span:

@State var area = MKCoordinateRegion()
  ...
Map(coordinateRegion: $area, annotationItems: [artwork]) { art work in
  MapMarker(coordinate: art work.coordinate)
}
.onAppear {
  area.middle = art work.coordinate
  area.span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
}

Refresh the preview or construct and run the app, and navigate to the map:

Maps view of Kuhio Beach

Xcode 15 Beta Map

This yr’s Map deprecates all of the Xcode 12 initializers. As a substitute of bindings to MKCoordinateRegion or MKMapRect, you create a Map with MapCameraBounds or MapCameraPosition.

You’ll be able to create a MapCameraBounds worth with an MKCoordinateRegion or MKMapRect worth, plus minimal and most distances, or you possibly can create one utilizing solely minimal and most distances.

Or you possibly can create a Map utilizing no parameters in any respect!

Map & Marker

In LocationMap, remark out @State var area and substitute all of the Map code — Map(...) { ... }.onAppear { ... } — with this:

Map {
  Marker(art work.title, coordinate: art work.coordinate)
}

MapMarker is deprecated, changed by Marker, the place you show a label, which is a View.

Maps zoomed in to marker

You get the identical balloon marker, however the map has zoomed proper in to it. To indicate roughly the identical area because the previous area, initialize Map with bounds:

Map(bounds:
      MapCameraBounds(minimumDistance: 4500,
                      maximumDistance: 4500))

Maps zoomed out from marker

Annotation

Along with Marker, there’s a brand new Annotation construction:

Annotation(art work.title,
           coordinate: art work.coordinate) {
  Picture(systemName: "particular person.bust")
    .padding(6)
    .foregroundStyle(.white)
    .background(Colour.blue)
}

Annotation on Maps marker

An Annotation shows each a label View and a content material View, so you possibly can customise your map pins. For instance, add these properties to Art work:

var image: String {
  change self-discipline {
  case "Monument", "Sculpture":
    return "particular person.bust"
  case "Mural":
    return "paintpalette"
  case "Plaque":
    return "particular person.textual content.rectangle"
  default:
    return "mappin"
  }
}

var background: Colour {
  change self-discipline {
  case "Monument", "Sculpture":
    return .blue
  case "Mural":
    return .mint
  case "Plaque":
    return .orange
  default:
    return .pink
  }
}

Every art work has a self-discipline property, and these new properties specify symbols and background colours for the most-populated disciplines.

Now, substitute your Marker and Annotation code with:

Marker(art work.title, systemImage: art work.image,
       coordinate: art work.coordinate)
.tint(art work.background)

Annotation(art work.title,
           coordinate: art work.coordinate,
           anchor: .topLeading) {
  Picture(systemName: art work.image)
    .padding(6)
    .foregroundStyle(.white)
    .background(art work.background)
}

Just like the deprecated MapMarker, Marker helps you to specify tint.

To see these customized symbols and colours at work, change the index of the artData merchandise within the preview to 1. This art work is a mural, so that you get mint-colored pins, and the annotation image is a paint palette:

Marker with paint palette annotation

You in all probability wouldn’t need to use each Marker and Annotation for a similar location, however whereas they’re each there, see how one can modify the place of the annotation’s anchor:

Annotation(art work.title,
           coordinate: art work.coordinate,
           anchor: .topLeading)  // add this argument

Marker and annotation, both with paint palette

The worth of anchor might be high, backside, main, trailing or combos, or you possibly can specify a CGPoint with x and y coordinates.

Map Model

And now for among the best new options: mapStyle. Add this modifier to Map after its closing brace:

.mapStyle(.imagery(elevation: .life like))

And alter bounds to zoom in:

Map(bounds:
      MapCameraBounds(minimumDistance: 1500,
                      maximumDistance: 1500))

Top-down satellite view of marker location

Shift-Possibility-drag to maneuver the map digital camera angle:

Angled satellite view of marker location

You can too add an initialPosition parameter to Map to set the map digital camera:

Map(
  initialPosition: .digital camera(MapCamera(
    centerCoordinate: art work.coordinate,
    distance: 1200,
    heading: 90,
    pitch: 60)),
  bounds:
    MapCameraBounds(minimumDistance: 1500,
                    maximumDistance: 1500)) {

Rotated satellite view of marker location

Now, you possibly can take an aerial tour round Honolulu by altering the artData merchandise within the preview. For instance, artData[12]:

Satellite view of golf course

There are solely 17 artworks, so don’t transcend artData[16].

The place to Go From Right here?

Obtain the ultimate venture utilizing Obtain supplies on the high or backside of this text.

On this article, you discovered about:

  • The brand new approach to create a Map.
  • The brand new Marker and Annotation buildings.
  • The brand new MapStyle construction.
  • The brand new MapCamera construction.

Meet MapKit for SwiftUI reveals off a number of nifty options, together with:

  • onMapCameraChange(frequency:), an occasion technique of MapPitchButton.
  • MapPolyline and MKRoute.
  • MapCompass and MapScaleView.

We hope you loved this tutorial, and when you have any questions or feedback, please be part of the discussion board dialogue under!

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles