> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/ios/maps/llms.txt)

# Use custom camera animations

Your browser doesn't support HTML5 video. Open [link to the video](https://docs.mapbox.com/ios/ios/assets/medias/CameraAnimators-62ae37fa0ba1e6c19008e45fd390256e.mp4).

This example demonstrates how to use Camera Animators in the **Mapbox Maps SDK for iOS**. The `ViewController` class includes functions to start a chain of camera animations that change the map's bearing, pitch, and zoom level. It allows the user to control the animation state with options to reset, run, or stop the camera animations. The example showcases [`CameraOptions`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/cameraoptions/) and camera animators to create smooth transitions and movements on the map. The animations include changing the bearing to -45 degrees, adjusting the pitch to 55 degrees, and zooming in to level 14. By interacting with the UI elements provided, the user can trigger and control these animated camera movements on the map.

> **Note: iOS Examples App Available**
> 
> This example code is part of the **Maps SDK for iOS Examples App**, a working iOS project [available on Github](https://github.com/mapbox/mapbox-maps-ios/tree/11.29.0/Sources/Examples). iOS developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.
> 
> See our [Run the Maps SDK for iOS Examples App](https://docs.mapbox.com/help/tutorials/maps-sdk-ios-examples-app/) tutorial for step-by-step instructions.

**Swift**

Title: `CameraAnimatorsExample.swift`

[View on GitHub](https://github.com/mapbox/mapbox-maps-ios/blob/main/Sources/Examples/All%20Examples/CameraAnimatorsExample.swift)

```swift
import UIKit
import MapboxMaps
import os

final class ViewController: UIViewController {
    private var mapView: MapView!
    private var cancelables = Set<AnyCancelable>()

    lazy var barButtonItem = UIBarButtonItem(title: nil, style: .plain, target: self, action: #selector(barButtonTap(_:)))

    // Coordinate in New York City
    let newYorkCamera = CameraOptions(center: CLLocationCoordinate2D(latitude: 40.7128,
                                                                     longitude: -74.0060),
                                      zoom: 16,
                                      bearing: 12,
                                      pitch: 60.340)

    override func viewDidLoad() {
        super.viewDidLoad()

        mapView = MapView(frame: view.bounds)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(mapView)

        animationState = .reset

        // Allows the delegate to receive information about map events.
        mapView.mapboxMap.onMapLoaded.observeNext { _ in
            self.navigationItem.rightBarButtonItem = self.barButtonItem
            
        }.store(in: &cancelables)
    }

    enum AnimationState {
        case reset
        case run
        case stop

        func next() -> AnimationState {
            switch self {
            case .reset: .run
            case .run:   .stop
            case .stop:  .reset
            }
        }

        var title: String {
            switch self {
            case .reset: "Reset"
            case .run:   "Run"
            case .stop:  "Stop"
            }
        }
    }

    var animationState: AnimationState = .reset {
        didSet {
            barButtonItem.title = animationState.next().title
            switch animationState {
            case .reset:
                // Center the map over New York City.
                mapView.mapboxMap.setCamera(to: newYorkCamera)
            case .run:
                startCameraAnimations()
            case .stop:
                mapView.camera.cancelAnimations()
            }
        }
    }

    @objc func barButtonTap(_ barButtonItem: UIBarButtonItem) {
        animationState = animationState.next()
    }

    // Start a chain of camera animations
    func startCameraAnimations() {
        os_log(.default, "Animating zoom from zoom to lvl 14")

        // Declare an animator that changes the map's bearing
        let bearingAnimator = mapView.camera.makeAnimator(duration: 4, curve: .easeInOut) { (transition) in
            transition.bearing.toValue = -45
        }

        bearingAnimator.addCompletion { position in
            os_log(.default, "All animations complete!")
            if position == .end {
                self.animationState = .stop
            }
        }
        bearingAnimator.onStarted.observe {
            os_log(.default, "Bearing animator has started")
        }.store(in: &cancelables)

        // Declare an animator that changes the map's pitch.
        let pitchAnimator = mapView.camera.makeAnimator(duration: 2, curve: .easeInOut) { (transition) in
            transition.pitch.toValue = 55
        }

        // Begin the bearing animation once the pitch animation has finished.
        pitchAnimator.addCompletion { _ in
            os_log(.default, "Animating camera bearing to 45 degrees")
            bearingAnimator.startAnimation()
        }

        // Declare an animator that changes the map's zoom level.
        let zoomAnimator = self.mapView.camera.makeAnimator(duration: 4, curve: .easeInOut) { (transition) in
            transition.zoom.toValue = 14
        }

        // Begin the pitch animation once the zoom animation has finished.
        zoomAnimator.addCompletion { _ in
            os_log(.default, "Animating camera pitch to 55 degrees")
            pitchAnimator.startAnimation()
        }

        // Begin the zoom animation.
        zoomAnimator.startAnimation()
    }
}
```