BS
BleepingSwift
Published on
3 min read

> How to Preview Live Activities in SwiftUI

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

Building the UI for a Live Activity usually means a lot of back and forth: tweak the layout, build, start the activity, check the result, repeat. Xcode's #Preview macro cuts that loop short by letting you preview your Live Activity views right in the canvas, just like any other SwiftUI view.

The key is the as: parameter, which tells the preview what kind of Live Activity presentation to render. You can preview the expanded Dynamic Island, the compact views, the minimal view, or the Lock Screen content.

Setting Up a Preview

To preview a Live Activity, you need your ActivityAttributes type and at least one sample ContentState. Here's a complete example using a server monitoring activity:

import WidgetKit
import SwiftUI

struct ServerAttributes: ActivityAttributes {
    var serverName: String

    struct ContentState: Codable, Hashable {
        var currentCpuUsage: Double
        var currentMemoryUsage: Int
    }
}

With your attributes defined, you can preview any presentation of the Dynamic Island. The #Preview macro accepts a display name, the presentation kind via as:, and the attributes instance via using:. You then provide one or more content states in the contentStates closure, which the preview canvas lets you cycle through:

import WidgetKit
import SwiftUI

#Preview("Expanded", as: .dynamicIsland(.expanded), using: ServerAttributes(serverName: "Preview Server")) {
    ServerDetailsActivityConfiguration()
} contentStates: {
    ServerAttributes.ContentState(currentCpuUsage: 0.752, currentMemoryUsage: 109232)
    ServerAttributes.ContentState(currentCpuUsage: 0.681, currentMemoryUsage: 87563)
}

This renders the expanded Dynamic Island view right in the Xcode canvas. You can provide multiple content states to see how your layout handles different data without restarting the activity each time.

Dynamic Island Presentation Kinds

The dynamicIsland(_:) method accepts a DynamicIslandPreviewViewState that controls which presentation you see. There are four options:

.expanded renders the full expanded view that users see when they long-press the Dynamic Island.

.compactLeading and .compactTrailing show the compact views that appear side by side when your app is the only one running a Live Activity.

.minimal shows the small circular view used when multiple Live Activities are running at the same time.

import WidgetKit
import SwiftUI

#Preview("Compact Leading", as: .dynamicIsland(.compactLeading), using: ServerAttributes(serverName: "Web-01")) {
    ServerDetailsActivityConfiguration()
} contentStates: {
    ServerAttributes.ContentState(currentCpuUsage: 0.45, currentMemoryUsage: 62000)
}

#Preview("Minimal", as: .dynamicIsland(.minimal), using: ServerAttributes(serverName: "Web-01")) {
    ServerDetailsActivityConfiguration()
} contentStates: {
    ServerAttributes.ContentState(currentCpuUsage: 0.92, currentMemoryUsage: 120000)
}

Previewing the Lock Screen Content

Live Activities also appear on the Lock Screen. To preview that presentation, use .content instead of .dynamicIsland:

import WidgetKit
import SwiftUI

#Preview("Lock Screen", as: .content, using: ServerAttributes(serverName: "Production DB")) {
    ServerDetailsActivityConfiguration()
} contentStates: {
    ServerAttributes.ContentState(currentCpuUsage: 0.33, currentMemoryUsage: 45000)
}

This is especially useful since the Lock Screen layout has more room than the Dynamic Island and often needs its own design attention.

Tips for Effective Previews

Providing multiple content states is the biggest time saver. Think about edge cases: what happens when a value is at 0% versus 100%? What about long strings that might clip? Each state you add to the contentStates closure becomes a separate preview you can flip through in the canvas.

If your preview isn't rendering, make sure the file is part of your widget extension target, not the main app target. The #Preview macro for Live Activities needs access to your ActivityConfiguration, which lives in the widget extension.

For the full API reference, see Apple's documentation on Preview(_:as:using:widget:contentStates:).

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.