Architecture • 22 August 2026 • Written by Mansi

Live Activities in iOS: Dynamic Island Layout Customization

Live Activities in iOS: Dynamic Island Layout Customization

Live Activities in iOS: Dynamic Island Layout Customization

Live Activities display real-time information on the Lock Screen and in the Dynamic Island. Whether tracking a delivery status, presenting a sports score, or monitoring active tasks, the layout must adapt as the event progresses. Instead of presenting a static view, your widget extension must handle dynamic layout transitions based on updating state properties.

Using ActivityKit and SwiftUI, you can build activities that respond to server-push payloads or local background updates, shifting between compact, minimal, and expanded layouts.


Defining Dynamic Attributes

A Live Activity is composed of static attributes (properties that do not change over the activity’s lifetime, like order IDs or product names) and dynamic content state (properties that update frequently, like status codes or arrival times).

import ActivityKit
import SwiftUI

struct RideDeliveryAttributes: ActivityAttributes {
    public struct ContentState: Codable, Hashable {
        // Developer Thoughts: We keep the state properties lightweight.
        // Activity state updates are transmitted via remote push notifications,
        // which have a strict size limit of 4KB.
        var status: String
        var estimatedArrivalMinutes: Int
        var dynamicAccentColorHex: String
    }
    
    // Static property
    var driverName: String
}

Configuring the Dynamic Island Layout

In your Widget Extension, you implement the ActivityConfiguration to declare how the activity should look in the compact, minimal, and expanded Dynamic Island presentations:

import WidgetKit
import SwiftUI

struct RideDeliveryWidget: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: RideDeliveryAttributes.self) { context in
            // Lock Screen Layout
            LockScreenView(state: context.state, driver: context.attributes.driverName)
        } dynamicIsland: { context in
            DynamicIsland {
                // Expanded Layout: Used when the user presses and holds the island
                DynamicIslandExpandedRegion(.leading) {
                    Label(context.state.status, systemImage: "car.fill")
                        .foregroundColor(Color(hex: context.state.dynamicAccentColorHex))
                }
                DynamicIslandExpandedRegion(.trailing) {
                    Text("\(context.state.estimatedArrivalMinutes)m")
                }
            } compactLeading: {
                // Compact Left: Default visual state on one side of the camera cutout
                Image(systemName: "car.fill")
                    .foregroundColor(Color(hex: context.state.dynamicAccentColorHex))
            } compactTrailing: {
                // Compact Right: Default visual state on the other side
                Text("\(context.state.estimatedArrivalMinutes)m")
            } minimal: {
                // Minimal: Used when multiple activities are active concurrently
                Image(systemName: "car.fill")
                    .foregroundColor(Color(hex: context.state.dynamicAccentColorHex))
            }
        }
    }
}

Summary

Live Activities use ActivityAttributes.ContentState to enable layout updates on the lock screen and Dynamic Island. By binding colors, icons, and text fields to dynamic state properties, you can adjust the interface layout as real-world events progress. Keep in mind that remote updates are size-limited, so complex data styling configurations should be resolved locally within the widget extension code.

References & Further Reading

Ready for more depth?

Master these concepts with our structured technical roadmap.

View Roadmap