# dotLottie iOS Player Usage Guide
Comprehensive guide for using the dotLottie iOS player. Covers DotLottiePlayerView (SwiftUI), DotLottiePlayerUIView (UIKit/AppKit), playback control, event handling, layout, markers, multi-animation, theming, and slots.

# dotLottie iOS Player Usage Guide

This guide shows you how to load animations, control playback, and handle events using the dotLottie iOS player. The player provides three approaches:

- **`DotLottiePlayerView`** — Declarative SwiftUI view with modifier API (recommended for SwiftUI).
- **`DotLottiePlayerUIView`** — UIKit/AppKit view with property-based API (recommended for UIKit).
- **`DotLottieAnimation`** — Lower-level view model used with `.view()`.

## SwiftUI with DotLottiePlayerView

`DotLottiePlayerView` is the recommended way to display animations in SwiftUI. It uses a builder-pattern modifier API.

### Basic usage

```swift
import SwiftUI
import DotLottie

struct ContentView: View {
    var body: some View {
        DotLottiePlayerView(animation: DotLottieAnimation(
            fileName: "animation",
            config: AnimationConfig(autoplay: true, loop: true)
        ))
        .looping()
        .playing()
        .frame(width: 300, height: 300)
    }
}
```

### Async loading with placeholder

Load an animation from a URL with a placeholder shown during loading:

```swift
struct AsyncAnimationView: View {
    var body: some View {
        DotLottiePlayerView({
            try await DotLottieAnimation(
                webURL: "https://example.com/animation.lottie",
                config: AnimationConfig(autoplay: true, loop: true)
            )
        }, placeholder: {
            ProgressView()
        })
        .looping()
        .playing()
        .frame(width: 300, height: 300)
    }
}
```

### Controlling playback with modifiers

```swift
DotLottiePlayerView(animation: animation)
    .playbackMode(.playing)         // or .paused
    .loopMode(.loop)                // or .playOnce
    .animationSpeed(2.0)            // double speed
    .mode(.reverse)                 // forward, reverse, bounce, bounceReverse
    .useFrameInterpolation(true)    // smooth playback at slow speeds
    .segments((0, 60))              // play frames 0–60
    .currentFrame(30)               // seek to frame 30
    .animationDidLoad {
        print("Animation loaded!")
    }
```

### Reloading an animation

Use `reloadAnimationTrigger` with a state variable to trigger a reload:

```swift
@State private var reloadTrigger = false

DotLottiePlayerView(animation: animation)
    .reloadAnimationTrigger(reloadTrigger, showPlaceholder: true)

Button("Reload") {
    reloadTrigger.toggle()
}
```

## UIKit with DotLottiePlayerUIView

`DotLottiePlayerUIView` is the recommended way to display animations in UIKit. It provides convenience initializers and a property-based API.

### Basic usage

```swift
import UIKit
import DotLottie

class ViewController: UIViewController {
    var playerView: DotLottiePlayerUIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        playerView = DotLottiePlayerUIView(
            name: "animation",
            config: AnimationConfig(autoplay: true, loop: true)
        )
        playerView.frame = CGRect(x: 50, y: 100, width: 300, height: 300)
        view.addSubview(playerView)
    }
}
```

### Loading from different sources

```swift
// From a file path
let player = DotLottiePlayerUIView(
    filePath: "/path/to/animation.lottie",
    config: AnimationConfig(autoplay: true, loop: true)
)

// From a URL
let player = DotLottiePlayerUIView(
    url: URL(string: "https://example.com/animation.lottie")!,
    config: AnimationConfig(autoplay: true, loop: true)
)

// From a JSON string
let player = DotLottiePlayerUIView(
    animationData: jsonString,
    config: AnimationConfig(autoplay: true, loop: true)
)

// From raw .lottie Data
let player = DotLottiePlayerUIView(
    dotLottieData: data,
    config: AnimationConfig(autoplay: true, loop: true)
)
```

### Controlling playback via properties

```swift
playerView.loopMode = .loop             // .playOnce or .loop
playerView.animationSpeed = 1.5         // speed multiplier
playerView.mode = .reverse              // forward, reverse, bounce, bounceReverse
playerView.useFrameInterpolation = true
playerView.segments = (0, 60)           // play frames 0–60

// Read state
let isPlaying = playerView.isAnimationPlaying
let frame = playerView.currentFrame
let progress = playerView.currentProgress
let total = playerView.totalFrames
```

### Playback methods

```swift
playerView.play()
playerView.pause()
playerView.stop()

// Play between progress values
playerView.play(fromProgress: 0.0, toProgress: 0.5, loopMode: .playOnce)

// Play between frames
playerView.play(fromFrame: 0, toFrame: 60, loopMode: .loop)

// Play a marker segment
playerView.play(marker: "intro", loopMode: .playOnce)

// Play between two markers
playerView.play(fromMarker: "intro", toMarker: "outro", loopMode: .loop)

// Seek
playerView.setFrame(30)
playerView.setProgress(0.5)
```

### Animation loaded callback

```swift
playerView.animationLoaded = {
    print("Animation is ready!")
}
```

## Using DotLottieAnimation (Lower-Level)

`DotLottieAnimation` is a view model that provides direct control. Use `.view()` for both SwiftUI and UIKit.

### SwiftUI

```swift
import SwiftUI
import DotLottie

struct ContentView: View {
    @StateObject var animation = DotLottieAnimation(
        fileName: "animation",
        config: AnimationConfig(autoplay: true, loop: true)
    )

    var body: some View {
        VStack {
            animation.view()
                .frame(width: 300, height: 300)

            HStack {
                Button("Play") { animation.play() }
                Button("Pause") { animation.pause() }
                Button("Stop") { animation.stop() }
            }
        }
    }
}
```

### UIKit

```swift
import UIKit
import DotLottie

class ViewController: UIViewController {
    var dotLottieAnimation: DotLottieAnimation?

    override func viewDidLoad() {
        super.viewDidLoad()

        let config = AnimationConfig(autoplay: true, loop: true)
        dotLottieAnimation = DotLottieAnimation(fileName: "animation", config: config)

        if let animation = dotLottieAnimation {
            let animationView = animation.view()
            animationView.frame = CGRect(x: 50, y: 100, width: 300, height: 300)
            view.addSubview(animationView)
        }
    }
}
```

### Loading from URL

```swift
dotLottieAnimation = DotLottieAnimation(
    webURL: "https://example.com/animation.lottie",
    config: AnimationConfig(autoplay: true, loop: true)
)
```

## Playback Control

Control animation playback using methods on the `DotLottieAnimation` instance:

```swift
// Start playing
dotLottieAnimation?.play()

// Pause
dotLottieAnimation?.pause()

// Stop and reset to initial frame
dotLottieAnimation?.stop()

// Set looping
dotLottieAnimation?.setLoop(loop: true)

// Set speed (1.0 = normal)
dotLottieAnimation?.setSpeed(speed: 2.0)

// Set playback mode
dotLottieAnimation?.setMode(mode: .reverse)

// Seek to a specific frame
dotLottieAnimation?.setFrame(frame: 50.0)

// Seek to a progress value (0.0–1.0)
dotLottieAnimation?.setProgress(progress: 0.5)

// Play from a specific frame
dotLottieAnimation?.play(fromFrame: 10.0)

// Play from a specific progress
dotLottieAnimation?.play(fromProgress: 0.25)
```

## Event Handling

Subscribe an `Observer` to receive animation playback events.

```swift
class MyObserver: Observer {
    func onComplete() { print("Animation Completed") }
    func onFrame(frameNo: Float) { }
    func onLoad() { print("Animation Loaded") }
    func onLoadError() { print("Load Error") }
    func onLoop(loopCount: UInt32) { print("Looped \(loopCount) times") }
    func onPause() { print("Paused") }
    func onPlay() { print("Playing") }
    func onRender(frameNo: Float) { }
    func onStop() { print("Stopped") }
}

let animation = DotLottieAnimation(fileName: "animation", config: config)
let myObserver = MyObserver()

// Subscribe
animation.subscribe(observer: myObserver)

// Unsubscribe when done
animation.unsubscribe(observer: myObserver)
```

## Layout Configuration

Define how the animation fits and aligns within the view bounds using the `Layout` object in `AnimationConfig`.

```swift
let layoutConfig = Layout(
    fit: .cover,          // .contain, .cover, .fill, .fitWidth, .fitHeight, .none
    align: [0.0, 0.0]    // [x, y]: [0,0]=TopLeft, [0.5,0.5]=Center, [1,1]=BottomRight
)

let config = AnimationConfig(layout: layoutConfig)
let anim = DotLottieAnimation(fileName: "animation", config: config)
```

| Property | Type      | Default      | Description                                                                                  |
| -------- | --------- | ------------ | -------------------------------------------------------------------------------------------- |
| `fit`    | `Fit`     | `.contain`   | How the animation scales: `.contain`, `.cover`, `.fill`, `.fitWidth`, `.fitHeight`, `.none`. |
| `align`  | `[Float]` | `[0.5, 0.5]` | Alignment `[x, y]`. `[0, 0]` = top-left, `[0.5, 0.5]` = center, `[1, 1]` = bottom-right.     |

## Using Markers

Control playback based on named markers defined within the Lottie animation.

**List Markers:**

```swift
let markers = dotLottieAnimation?.markers()
print("Available markers: \(markers ?? [])")
```

**Play a Segment Defined by a Marker on Load:**

```swift
let config = AnimationConfig(marker: "intro")
let anim = DotLottieAnimation(fileName: "animation", config: config)
```

**Set Marker Programmatically:**

```swift
dotLottieAnimation?.setMarker(marker: "outro")
dotLottieAnimation?.play()
```

**Reset/Clear Marker:**

```swift
dotLottieAnimation?.setMarker(marker: "")
```

## Handling Multiple Animations

A single `.lottie` file can contain multiple animations.

**List Animations:**

```swift
if let manifest = dotLottieAnimation?.manifest() {
    print("Available animation IDs: \(manifest.animations.map { $0.id })")
}
```

**Load and Play a Specific Animation by ID:**

```swift
dotLottieAnimation?.loadAnimation(animationId: "explosion")
dotLottieAnimation?.play()
```

**Load via Config:**

```swift
let config = AnimationConfig(animationId: "explosion")
let anim = DotLottieAnimation(fileName: "multi_animation", config: config)
```

## Theming

Apply themes defined within the `.lottie` file or load theme data dynamically. See [Theming Blog Post](https://lottiefiles.com/blog/working-with-lottie-animations/how-to-add-themes-to-lottie-animations-in-lottie-creator) for theme creation details.

**Load Theme by ID on Init:**

```swift
let config = AnimationConfig(themeId: "darkMode")
let anim = DotLottieAnimation(fileName: "themedAnimation", config: config)
```

**Set Theme Programmatically:**

```swift
let success = dotLottieAnimation?.setTheme("lightMode")
```

**Load Theme Data Dynamically:**

```swift
let success = dotLottieAnimation?.setThemeData(themeJSONData)
```

**Reset Theme:**

```swift
dotLottieAnimation?.resetTheme()
```

**Get Active Theme ID:**

```swift
let currentTheme = dotLottieAnimation?.activeThemeId()
```

## Slots

Slots allow dynamic replacement of animation elements. You can use a raw JSON string or typed slot methods.

### Raw JSON Slots

```swift
let success = dotLottieAnimation?.setSlots(slotJSONData)
```

### Typed Slot Methods

```swift
// Set a color slot (RGB values from 0.0 to 1.0)
dotLottieAnimation?.setColorSlot(slotId: "primaryColor", r: 1.0, g: 0.0, b: 0.5)

// Set a text slot
dotLottieAnimation?.setTextSlot(slotId: "title", text: "Hello World")

// Set a scalar slot
dotLottieAnimation?.setScalarSlot(slotId: "opacity", value: 0.8)

// Set a vector slot
dotLottieAnimation?.setVectorSlot(slotId: "scale", x: 2.0, y: 2.0)

// Set a position slot
dotLottieAnimation?.setPositionSlot(slotId: "offset", x: 100.0, y: 50.0)

// Set an image slot from a file path
dotLottieAnimation?.setImageSlotPath(slotId: "avatar", path: "/path/to/image.png")

// Set an image slot from a data URL
dotLottieAnimation?.setImageSlotDataUrl(slotId: "avatar", dataUrl: "data:image/png;base64,...")

// Clear a specific slot
dotLottieAnimation?.clearSlot(slotId: "primaryColor")

// Clear all slots
dotLottieAnimation?.clearSlots()
```

## Using State Machines (Interactivity)

> **Note:** Interactivity using state machines is currently in its early stages of development and considered experimental. The API might change in future releases.

Interact with state machines defined within your `.lottie` file to create interactive animations.

**1. Load and Start a State Machine:**

```swift
if dotLottieAnimation?.stateMachineLoad(id: "button_interactions") ?? false {
    print("State machine loaded successfully.")

    if dotLottieAnimation?.stateMachineStart() ?? false {
        print("State machine started.")
    }
}
```

**2. Post Events to the State Machine:**

```swift
// Post a click event
dotLottieAnimation?.stateMachinePostEvent(Event.click(x: 150, y: 150))

// Post a pointer event
dotLottieAnimation?.stateMachinePostEvent(Event.pointerDown(x: 10, y: 20))

// Post a completion event
dotLottieAnimation?.stateMachinePostEvent(Event.onComplete)

// Fire a named event
dotLottieAnimation?.stateMachineFire(event: "click")
```

**3. Stop the State Machine:**

```swift
dotLottieAnimation?.stateMachineStop()
```

For more details, see [Understanding State Machines](/en/runtimes/distributions/ios/v0.x/state-machines).
