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 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.