avatarDevTechie

Summary

The article provides a tutorial on using mapCameraKeyframeAnimator in SwiftUI and iOS 17 to create custom map animations, specifically demonstrating how to animate a flyover from Alcatraz to the Golden Gate Bridge in a San Francisco attractions app.

Abstract

The article titled "Mastering MapKit in SwiftUI & iOS 17 — Part 14" delves into the advanced features of MapKit for SwiftUI developers. It explains how to leverage mapCameraKeyframeAnimator to gain more control over map animations beyond the default subtle animations provided by MapKit. The tutorial guides readers through building an animation that flies from Alcatraz to the Golden Gate Bridge within a San Francisco Top Attractions app. It starts by setting up State properties to manage animation triggers and camera positions, then proceeds to render a map view and implement a button to initiate the animation. The article concludes by detailing the use of KeyframeTrack to animate the map camera's pitch, heading, and center coordinate, with a call to action for readers to engage with the content and follow the author's website for more information.

Opinions

  • The author implies that the default animations provided by MapKit may be insufficient for certain use cases, necessitating the use of mapCameraKeyframeAnimator for more sophisticated animations.
  • The tutorial is structured to be hands-on, encouraging developers to follow along and build the animation experience step by step.
  • The use of keyframes is presented as a powerful way to create smooth and complex animations in MapKit, with the example illustrating a practical application of these concepts.
  • The article suggests that user interaction should take precedence over ongoing animations, as gestures by the user will terminate the animation to allow for immediate camera control.
  • The author expresses enthusiasm for sharing knowledge and seeks to engage the reader by inviting them to clap and follow for more content, indicating a commitment to community and continuous learning.

Mastering MapKit in SwiftUI & iOS 17 — Part 14

Mastering MapKit in SwiftUI & iOS 17 — Part 14

MapKit provides some subtle animations out of the box, but if we need a bit more control over the animation, we can leverage the power of mapCameraKeyframeAnimator. It utilizes the provided keyframes to animate the camera of a Map view when the given trigger value changes. Upon the trigger value alteration, the map invokes the keyframes closure to generate the keyframes responsible for animating the camera. The animation will persist for the duration of the specified keyframes. If the user performs a gesture while the animation is ongoing, it will be promptly terminated, enabling user interaction to assume control of the camera.

Let’s build an experience where we will fly from Alcatraz to GoldenGate bridge in SF Top Attractions app.

This is what we will be building

Start with a State property to control the animation.

import SwiftUI
import MapKit

struct MapCameraAnimator: View {
    @State var animate: Bool = false

We will fetch and store coordinates for both locations in local variables.

import SwiftUI
import MapKit

struct MapCameraAnimator: View {
    @State var animate: Bool = false
    
    let alcatraz = SFPlace.topAttractions[0].coordinates
    let goldenGate = SFPlace.topAttractions[1].coordinates

Next, create another State property to set map camera position on the top of Alcatraz.

import SwiftUI
import MapKit

struct MapCameraAnimator: View {
    @State var animate: Bool = false
    
    let alcatraz = SFPlace.topAttractions[0].coordinates
    let goldenGate = SFPlace.topAttractions[1].coordinates
    
    @State private var mapCameraPosition = MapCameraPosition.camera(MapCamera(
        centerCoordinate: SFPlace.topAttractions[0].coordinates, distance: 5000))

Let’s use the map view to render map on the screen

import SwiftUI
import MapKit

struct MapCameraAnimator: View {
    @State var animate: Bool = false
    
    let alcatraz = SFPlace.topAttractions[0].coordinates
    let goldenGate = SFPlace.topAttractions[1].coordinates
    
    @State private var mapCameraPosition = MapCameraPosition.camera(MapCamera(
        centerCoordinate: SFPlace.topAttractions[0].coordinates, distance: 5000))
    
    var body: some View {
        VStack {
            Map(position: $mapCameraPosition)
                .mapStyle(.standard(elevation: .realistic))

We will use a button control to trigger the animation so let’s add that inside a safeAreaInset

import SwiftUI
import MapKit

struct MapCameraAnimator: View {
    @State var animate: Bool = false
    
    let alcatraz = SFPlace.topAttractions[0].coordinates
    let goldenGate = SFPlace.topAttractions[1].coordinates
    
    @State private var mapCameraPosition = MapCameraPosition.camera(MapCamera(
        centerCoordinate: SFPlace.topAttractions[0].coordinates, distance: 5000))
    
    var body: some View {
        VStack {
            Map(position: $mapCameraPosition)
                .mapStyle(.standard(elevation: .realistic))
                .safeAreaInset(edge: .bottom) {
                    Button("Animate") {
                        animate.toggle()
                    }
                }

Now we are ready to add keyframe animation to the map, we will use mapCameraKeyframeAnimator modifier passing the animate State property as the trigger value.

import SwiftUI
import MapKit

struct MapCameraAnimator: View {
    @State var animate: Bool = false
    
    let alcatraz = SFPlace.topAttractions[0].coordinates
    let goldenGate = SFPlace.topAttractions[1].coordinates
    
    @State private var mapCameraPosition = MapCameraPosition.camera(MapCamera(
        centerCoordinate: SFPlace.topAttractions[0].coordinates, distance: 5000))
    
    var body: some View {
        VStack {
            Map(position: $mapCameraPosition)
                .mapStyle(.standard(elevation: .realistic))
                .safeAreaInset(edge: .bottom) {
                    Button("Animate") {
                        animate.toggle()
                    }
                }
                .mapCameraKeyframeAnimator(trigger: animate) { _ in

We will use KeyframeTrack which defines a sequence of keyframes animating a single property of a root type. For our use case, we will animate pitch, heading and centerCoordinate values.

import SwiftUI
import MapKit

struct MapCameraAnimator: View {
    @State var animate: Bool = false
    
    let alcatraz = SFPlace.topAttractions[0].coordinates
    let goldenGate = SFPlace.topAttractions[1].coordinates
    
    @State private var mapCameraPosition = MapCameraPosition.camera(MapCamera(
        centerCoordinate: SFPlace.topAttractions[0].coordinates, distance: 5000))
    
    var body: some View {
        VStack {
            Map(position: $mapCameraPosition)
                .mapStyle(.standard(elevation: .realistic))
                .safeAreaInset(edge: .bottom) {
                    Button("Animate") {
                        animate.toggle()
                    }
                }
                .mapCameraKeyframeAnimator(trigger: animate) { _ in
                    
                    KeyframeTrack(\.pitch) {
                        LinearKeyframe(0, duration: 1.0)
                        LinearKeyframe(75, duration: 1.0)
                    }
                    
                    KeyframeTrack(\.heading) {
                        LinearKeyframe(0, duration: 1.0)
                        LinearKeyframe(-70, duration: 1.0)
                    }
                    KeyframeTrack(\.centerCoordinate) {
                        LinearKeyframe(alcatraz, duration: 1.0)
                        LinearKeyframe(alcatraz, duration: 1.0)
                        LinearKeyframe(goldenGate, duration: 10)
                    }
                }
        }
    }
}

Time to build and run

With that we have reached the end of this article. Thank you once again for reading. If you liked this, don’t forget to 👏 and follow 😍. Also visit us at https://www.devtechie.com

Swiftui
Mapkit
iOS
Ios 17
Devtechie
Recommended from ReadMedium