ActivityConfiguration | Apple Developer
Live Activities | Apple Developer
π WidgetKit μ΄λ ?
π μ κΈνλ©΄ μμ ― λ§λ€κΈ°(WidgetKit)
μ΄λ² κΈμμλ WidgetKitμ μ¬μ©νλ LiveActivityμ λν΄μ μ΄ν΄λ³΄λλ‘ νκ² λ€.
LiveActivityλ iOS 16 λ²μ μμ μλ‘ λμ λ κΈ°λ₯μ΄λ€.
μ¬μ©μκ° μ€μκ°μΌλ‘ μ§ν μ€μΈ μμ μ ν νλ©΄μ΄λ μ κΈ νλ©΄μμ μ§μ μΆμ ν μ μλλ‘ μ§μνμ¬ μ¬μ©μμκ² μ€μκ°μΌλ‘ μ λ°μ΄νΈλλ μ 보λ₯Ό μ 곡ν μ μλλ‘ νλ κΈ°λ₯μ΄λ€.
μ€μκ° μ 보λ₯Ό νμνκ³ μ λ°μ΄νΈ ν μ μμΌλ©°, μμ λ°°λ¬, νμμ λμ°© μκ°, μ΄λ κ²½κΈ° μ μ λ° μ€μκ° κ²½λ‘ νμ λ±μ μλΉμ€μμ μ μ©νκ² μ 보λ₯Ό μ κ³΅ν΄ μ€ μ μλ€.
μ¬κΈ°μ 16.2 λ²μ λΆν° DynamicIslandλ₯Ό μ§μνλ λλ°μ΄μ€μ λν΄μλ κΈ°μ‘΄ λ ΈμΉ μμμ μΆκ°μ μΈ μ€μκ° μ 보 μ 곡λ κ°λ₯ν κΈ°λ₯μ΄λ€.
LiveActivityλ WidgetKitκ³Ό ν¨κ» ꡬμ±μ΄ κ°λ₯νκ³ ActivityKitμ μ¬μ©ν΄ μ€μκ° λ°μ΄ν°λ₯Ό μ λ°μ΄νΈνκ³ λ³κ²½ν μ μμ΄ μ¬μ©μκ° μ±μ μ΄μ§ μλλΌλ μνλ μ€μκ° λ°μ΄ν°λ₯Ό λ°μλ³Ό μ μμ΄ μ¬μ©μ κ²½νμ ν¬κ² ν₯μμν¬ μ μλ κ°λ ₯ν λꡬμ΄λ€.
LiveActivity μ¬μ©μ μν΄μλ μμ ―μ λ§λλ λ°©λ²κ³Ό λμΌνκ² WidgetKitμ μ¬μ©ν΄μΌ νλ€.
File > New > Target
Widget Extensionμ μ νν΄μ£Όμ.
WidgetKitμ μ΄λ¦μ λ£μ΄μ£Όκ³ "include Live Activity"λ₯Ό μ ννμ¬ LiveActivityλ μΆκ°ν΄ μ£Όλ©΄ λλ€.
μ¬κΈ°μ "include Configuration App Intent"λ₯Ό 체ν¬νκ² λλ©΄ WidgetKitμ κΈ°λ₯ μ€ νλμΈ ν μμ ―μ μμ± νμ μ IntentConfiguration νμ μΌλ‘ μμ±λκ² λκ³ , 체ν¬λ₯Ό νμ§ μκ² λλ©΄ StaticConfiguration νμ μ΄ μ μ©λλ€.
ν μμ ―μ μ’ λ₯λ₯Ό μ λͺ¨λ₯΄μλ λΆλ€μ μν΄ κ°λ¨νκ² μ€λͺ νμλ©΄, ν μμ ―μ νΈμ§μ΄ κ°λ₯ν μμ ―μ IntentConfiguration νμ μ΄λΌνκ³ μμ ―μ νΈμ§μ΄ λΆκ°λ₯ν μμ ―μ StaticConfigurationμ΄λΌκ³ νλ€.
WidgetKitμ μ λ°μ μΈ λ΄μ©λ€μ μμΈν μκ³ μΆλ€λ©΄ μ΄μ μ μμ±ν κΈμ μ°Έκ³ νμκΈΈ λ°λλ€.
μ μμ μΌλ‘ μμ±μ΄ λλ©΄ μμ ― νμΌκ³Ό LiveActivity μμ ― νμΌμ΄ κ°κ° μμ±λμ΄ μμ κ²μ΄λ€.
μ΄ μ€ LiveActivity νμΌμ μ¬μ©νλ©΄ λκ³ , μμ ― νμΌμ ν/μ κΈ μμ ―μ μ¬μ©λλ νμΌμ΄λ νμμ λ°λΌ ν΄λΉ νμΌμ μ¬μ©νμκ±°λ μ§μμ£Όμλ©΄ λλ€.
λ§μΌ λ³ΈμΈμ μλΉμ€κ° ν/μ κΈ μμ ―μ μ¬μ©ν νμκ° μκ³ , μ€λ‘μ§ LiveActivityλ§ μ¬μ©νκΈΈ μνλ€λ©΄ μλ μ²λΌ μ½λλ₯Ό μ μ©ν΄ μ£Όλ©΄ λλ€.
WidgetKitμ μΆκ°νλ©΄ κΈ°λ³Έμ μΌλ‘λ ν μμ ―μ μ§μλκ² λλ€.
WidgetKitμ μμ±λ WidgetBundle νμΌμ μΆκ°λμ΄ μλ ν μμ ― κ΄λ ¨ κ°μ²΄λ₯Ό μ¬μ©νμ§ μμΌμλ©΄ λλ€.
@main
struct LiveActivityWidgetBundle: WidgetBundle {
var body: some Widget {
// LiveActivityWidget()
LiveActivityWidgetLiveActivity()
}
}
LiveActivityλ iOS 16.2λ²μ λΆν° μ¬μ©μ΄ κ°λ₯νκΈ° λλ¬Έμ, iOS 16.2μ΄ν λ²μ μ νκ²νλ μλΉμ€μΈ κ²½μ° μλμ κ°μ΄ μ½λλ₯Ό μΆκ°ν΄μ£Όμ΄μΌ νλ€.
@main
struct TimerWIdgetBundle: WidgetBundle {
var body: some Widget {
TimerWIdget()
if #available(iOS 16.2, *) {
TimerWIdgetLiveActivity()
}
}
}
μ°μ LiveActivityκ° μ μμ μΌλ‘ λ ΈμΆλλμ§ ν μ€νΈλ₯Ό ν΄λ³΄μ.
Widget Extensionμ μμ±ν μ΄λ¦μ΄ μ μ λμΌν κ²½μ°λΌλ©΄ μλ μ½λλ₯Ό μ¬μ©ν΄ LiveActivityλ₯Ό μ€νμμΌ λ³Ό μ μλ€.
import SwiftUI
import ActivityKit
struct ContentView: View {
var body: some View {
VStack {
Button {
let attributes = TimerWIdgetAttributes(name: "Timer Sample")
let contentState = TimerWIdgetAttributes.ContentState(emoji: "π")
let content = ActivityContent(state: contentState, staleDate: nil)
do {
_ = try Activity<TimerWIdgetAttributes>.request(
attributes: attributes,
content: content,
pushType: nil
)
} catch {
print("LiveActivityManager: Error in LiveActivityManager: \(error.localizedDescription)")
}
}label: {
Text("Show")
}
}
.padding()
}
}
λ§μΌ attributes μ΄λ¦μ΄ λ€λ₯΄λ€λ©΄ Widet ν΄λμμ LiveActivity νμΌμμ μ°Ύμ μ μλ€.
μ¬κΈ°μ μ½λλ₯Ό λκ°μ΄ λ£μλλ°λ attributes κ°μ²΄λ₯Ό μ°Ύμ§ λͺ»νλ μλ¬κ° λ°μνμ κ²μ΄λ€.
μ΄κ±΄ λΉλ νκ²μ ν¬ν¨λμ΄ μμ§ μκΈ° λλ¬Έμ λ°μν λ¬Έμ λ‘ Target Membershipμμ μΆκ°ν΄ μ£Όλ©΄ λλ€.
LiveActivity νμΌλ‘ κ°μ Target Membershipμμ μ± νκ²μ μ νν΄μ ν¬ν¨μμΌ μ£Όλ©΄ κ°μ²΄λ₯Ό μ°Ύμ μ μλ€.
μ΄μ μ€νμμΌ λ³΄λλ‘ νμ.
LiveActivityκ° μ€νμ΄ λμ§ μλλ°, μμ§ LiveActivity μ§μμ νμ±ν μν€μ§ μμκΈ° λλ¬Έμ΄λ€.
Info.plistμ "Supports Live Activities"λ₯Ό μΆκ°νκ³ Valueλ₯Ό "YES"λ‘ μ€μ ν΄μ£Όλ©΄ λλ€.
μ΄μ μ μμ μΌλ‘ LiveActivityκ° μ€νλλ κ²μ νμΈν μ μλλ°, μ κΈνλ©΄μμ LiveActivityκ° λ ΈμΆμ΄ λκ³ , μ±μ λ°±κ·ΈλΌμ΄λλ‘ λ³΄λμ λμλ DynamicIslandμ λ±λ‘μ΄ μ λκ²μ νμΈν μ μλ€.
Supports Live Activities | |
---|---|
NO | YES |
![]() |
![]() |
κΈ°λ³Έμ μΈ μ€μ μ μλ£νμΌλ 본격μ μΌλ‘ LiveActivityμ λν΄μ μμ보λλ‘ νμ.
μ΄μ 본격μ μΌλ‘ LiveActivityμ UI ꡬ쑰 λΆν° μ¬μ© λ°©λ²κΉμ§ μμΈν λ€λ€λ³΄λλ‘ νκ³λ€.
LiveActivityλ₯Ό μ¬μ©νκΈ° μμ μ νν μ΄λ€ λΆλΆμμ μ¬μ©νλμ§λ₯Ό μκ³ μμ΄μΌ νκΈ° λλ¬Έμ UI μμκ° μ΄λμ μ¬μ©λλ 건μ§λ₯Ό νμΈν΄ 보λλ‘ νμ.
LiveActivity νμΌμ μ½λλ₯Ό νμΈν΄λ³΄λ©΄, Widget μ½λλ₯Ό νμΈν μ μλ€.
λ°λ‘ μ¬κΈ° μ½λμμ UIλ₯Ό κΎΈλ©°μ£Όλ©΄ λλλ° ActivityConfiguration, dynamicIsland μμλ₯Ό νμΈνλ©΄ λλ€.
![]() |
![]() |
![]() |
μμ μ΄λ―Έμ§λ₯Ό 보면 ν¬κ² 3κ°μ§μ ꡬ쑰λ₯Ό κ°μ§κ² λλ€.
ActivityConfigurationμμλ₯Ό μ¬μ©ν΄μ μ κΈνλ©΄μμ 보μ¬μ€ UIλ₯Ό μμ ν μ μκ³ , DynamicIslandμ κΈ°λ³Έ μμλ compact, λ€μ΄λλ―ΉμμΌλλμ νλλ μνμ μμλ DynamicIslandExpandedRegionμ μ¬μ©ν μ μλ€.
DynamicIslandλ₯Ό μμ£Ό μ¬μ©νμλ λΆλ€μ ꡬ쑰λ₯Ό μ μμκ² μ§λ§ ν¬κ² 3κ°μ§μ UI νμ μ΄ μ¬μ©λλ€.
μ¬κΈ°μ minimalμ 2κ° μ΄μμ LiveActivityμ±μ΄ ꡬλ μ€μΌλμλ§ λ ΈμΆλλ ꡬ쑰μ΄κ³ , 2κ° μ€ νλλ DynamicIslandμ λ°°μΉλκ³ , λλ¨Έμ§ νλλ λ 립μ μΈ μμμ νμλλλ° κΈ°μ€μ μ±μμ μ ν μ°μ μμλ₯Ό λ°λ₯΄κ² λλ€.
expand | compact | minimal |
---|---|---|
![]() |
![]() |
![]() |
μμμ μν μ½λλ₯Ό μ¬μ©ν΄μ LiveActivityλ₯Ό μ€νν΄ λ΄€λλ° μ νν LiveActivityλ₯Ό μ΄λ»κ² μ μ΄ν΄μΌ νλμ§μ λν΄μ μμ보μ.
LiveActivityλ ActivityKitμ μ¬μ©ν΄μ μ μ΄λ₯Ό ν μ μλ€.
ActivityKitμ ν΅ν μ μ΄λ μμ, μ λ°μ΄νΈ, μ’ λ£ μ΄λ κ² 3κ°μ§ κΈ°λ₯μ μ 곡νλ€.
λ¨Όμ LiveActivityλ₯Ό νμ±ν ν΄λ³΄λλ‘ νμ.
requestλ₯Ό μ¬μ©ν΄ LiveActivityλ₯Ό μ€νν μ μμΌλ©°, attributes, content, pushType λͺ¨λ νμλ‘ λ±λ‘ν΄μΌ νλ€.
attributes : μ μ μ΄νΈλ¦¬λ·°νΈ κ°μ²΄
let attributes = TimerWIdgetAttributes(name: "Timer Sample")
content : λμ μ΄νΈλ¦¬λ·°νΈ κ°μ²΄
contentStateλ₯Ό μ¬μ©ν΄ λμ μΌλ‘ 보μ¬μ£Όκ³ μ νλ λ°μ΄ν°λ₯Ό λκ²¨μ€ μ μμΌλ©°, ActivityContent κ°μ²΄λ₯Ό μμ±ν΄ μ£Όλ©΄ λλ€.let contentState = TimerWIdgetAttributes.ContentState(emoji: "π") let content = ActivityContent(state: contentState, staleDate: nil,relevanceScore: 1)
- staleDate: λ§λ£μκ°μΌλ‘, nil μ§μ μ 8μκ° ν μ’ λ£ (μ κΈνλ©΄ 12μκ°)
- relevanceScore: minimal μ°μ μμλ‘ 0~1λ‘ μ€μ
pushType : μ λ°μ΄νΈ νλμ λν νΈμ μλ¦Ό μ¬λΆ
nil μ¬μ©μ μ±μ μ λ°μ΄νΈλ‘λ§ νλμ λ³κ²½ν¨
μλμ κ°μ΄ LiveActivityλ₯Ό μμνλ©°, μμν¨κ³Ό λμμ μ κΈνλ©΄μλ λ ΈμΆλκΈ° μμνλ€.
private func start() {
let attributes = TimerWIdgetAttributes(name: "Timer Sample")
let contentState = TimerWIdgetAttributes.ContentState(emoji: "π")
let content = ActivityContent(state: contentState, staleDate: nil,relevanceScore: 1)
do {
_ = try Activity<TimerWIdgetAttributes>.request(
attributes: attributes,
content: content,
pushType: nil
)
} catch {
print("LiveActivityManager: Error in LiveActivityManager: \(error.localizedDescription)")
}
}
LiveActivityλ μ΅λ λ ΈμΆμκ°μ΄ μ ν΄μ Έ μλλ°, μ’ λ£ μκ°μ λ°λ‘ μ§μ νκ±°λ μ’ λ£λ₯Ό μμΌμ£Όμ§ μλλ€λ©΄ μ΅λ 8μκ° κΉμ§ λ ΈμΆμ΄ κ°λ₯νκ³ μ κΈνλ©΄μμλ μ΅λ 12μκ° κΉμ§ λ¨μμμ μ μλ€.
λμ λ°μ΄ν° μ¬μ©κ³Ό κ΄λ ¨ν΄μλ LiveActivityκ° μ체 μλλ°μ€μ μ€νλκΈ° λλ¬Έμ λ€νΈμν¬ μ κ·Όμ΄λ μμΉ λ°μ΄ν° μ
λ°μ΄νΈ λ±μ λ°μ΄ν°λ₯Ό λ°μ μ μκΈ° λλ¬Έμ λμ λ°μ΄ν°λ₯Ό μ¬μ©νκ³ μ νλ€λ©΄ μ±μ ActivityKitμ ν΅ν λμ λ°μ΄ν° μ λ¬μ΄λ ActivityKitμ νΈμλ₯Ό λ±λ‘ν΄ νΈμ μλ¦Όμ ν΅ν΄ λ°μ΄ν°λ₯Ό μ»μ μ μλ€.
νΈμ μλ¦Όμ ν΅ν λμ λ°μ΄ν°λ₯Ό κ°μ Έμ¬ λμλ 4KB μ΄μμ λ°μ΄ν°λ μ λ¬ λ°μ μ μμΌλ μ΄ μ μ κ³ λ €νμ
μΌ νλ€.
μ΄λ²μλ μ±μ μ΄λ²€νΈλ₯Ό λ°μμμΌ LiveActivityμ λ°μ΄ν°λ₯Ό μ λ°μ΄νΈνλ λ°©λ²μ λν΄μ μμ보μ.
λ¨Όμ νμ¬ νμ±νλ LiveActivityμ μ 보λ₯Ό κ°μ Έμ€λλ‘ νμ.
ActivityKitμ activitiesμ νμ¬ νλμ μ λ³΄κ° λ΄κ²¨μλ€.
for activity in Activity<TimerWIdgetAttributes>.activities {
// current LiveActivity
}
νλμ λν μ 보λ₯Ό κ°μ Έμ νμ±νλ μ‘ν°λΉν°μ λ°μ΄ν°λ₯Ό μ λ°μ΄νΈν μ μλ€.
ContentStateμ λ°μ΄ν°λ₯Ό λ³κ²½νκ³ μ νλ λ°μ΄ν°λ‘ λ±λ‘ν΄μ£Όλ©΄ λλ€.
updateμ contentλ νμλ‘ μ λ¬ν΄μΌνλ κ°μ μλλ€.
private func update() async{
let status = TimerWIdgetAttributes.ContentState(emoji: "Update")
let content = ActivityContent(state: status, staleDate: nil)
for activity in Activity<TimerWIdgetAttributes>.activities {
await activity.update(content)
}
}
λ§μ§λ§μΌλ‘ LiveActivityμ νλμ μ’ λ£μν€λ λ°©λ²μ΄λ€.
μ¬κΈ°μ μ’ λ£λ₯Ό νλ λ°©λ²μ 2κ°μ§ λ°©λ²μ΄ μλλ°, λ¨μν μ’ λ£λ§ ν μ μκ³ μμ μ κΈνλ©΄μμ μ§μμ€ μ μλ€.
μ΄λ²μλ update λ°©λ²κ³Ό λμΌνκ² νμ¬ νλ μ€μΈ μ‘ν°λΉν°λ₯Ό κ°μ Έμμ μ€ν μ€μΈ μ‘ν°λΉν°λ₯Ό μ’ λ£ν΄ μ£Όλλ‘ νμ.
private func end() async{
let finalStatus = TimerWIdgetAttributes.ContentState(emoji: "End")
let finalContent = ActivityContent(state: finalStatus, staleDate: nil)
for activity in Activity<TimerWIdgetAttributes>.activities {
await activity.end(finalContent)
}
}
dismissalPolicy
νλμ μ’ λ£νλ λ°©λ²μλ 3κ°μ§μ νμ μ΄ μλ€.
.default
LiveActivity κΈ°λ₯λ§ μ’ λ£await activity.end(finalContent,dismissalPolicy: .default)
.immediate
LiveActivity κΈ°λ₯ μ’ λ£ λ° μ κ±°await activity.end(finalContent,dismissalPolicy: .immediate)
.after(Date)
LiveActivityλ₯Ό μμ±ν μκ°μ μ’ λ£ λ° μ κ±°await activity.end(finalContent,dismissalPolicy: .after(Date()))
default | immediate | after(10μ΄ ν) |
---|---|---|
![]() |
![]() |
![]() |
LiveActivityμ μμ μ€ μ΄μ΄μ μ΄ν΄λ³Ό μμλ λ°λ‘ μμμ μ¬μ©ν΄λ³Έ
ActivityAttributes κ°μ²΄μ΄λ€.
ν΄λΉ κ°μ²΄μ ContentStateλ νμλ‘ μ¬μ©ν΄μΌ νλ©° ν΄λΉ νλμ λμ κ°μ²΄λ₯Ό μμ±ν μ μλλ‘ νλ©΄ λλ€.
λμ κ°μ²΄μ λ³μλ νλλ§ μ¬μ©ν΄μΌ νλ κ²μ μλκ³ , μ¬λ¬ λ³μλ€μ μ¬μ©νμ¬λ λλ LiveActivityμ 보μ¬μ£Όκ³ μ νλ μ μ ν ꡬ쑰λ₯Ό λ§λ€μ΄ νμ©ν΄ μ£Όλ©΄ λλ€.
μ°Έκ³ λ‘ κΈ°λ³Έ μ½λμ μμ±λμ΄ μλ name λ³μλ νμκ° μλλ€.
struct TimerWIdgetAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var emoji: String
}
// Fixed non-changing properties about your activity go here!
var name: String
}
λ§μ§λ§μΌλ‘ UIλ₯Ό ꡬμ±ν΄μ£Όλ Widget κ°μ²΄μ λν΄μ μμ보μ.
Widgetμ WidgetConfiguration νλ‘ν μ½μ λ°νν΄μΌ νλ©° LiveActivityλ ActivityConfigurationμ μ¬μ©ν μ μλ€.
ActivityConfiguration(for: TimerWIdgetAttributes.self) { context in
// Lock Scrren UI
} dynamicIsland: { context in
// DynamicIsland UI
}
)
LiveActivityμ μ κΈνλ©΄κ³Ό ν¨κ» ꡬμ±μ΄ κ°λ₯ν DynamicIslandμ λν΄μλ μμ보λλ‘ νμ.
μ κΈνλ©΄μμλ μ±μ νμ±ν μνμμλ μ κΈνλ©΄μ λ ΈμΆλμ§λ§, DynamicIslandλ μ±μ΄ λΉνμ± μνμΈ κ²½μ°μλ§ λ ΈμΆλκ² λλ€.
DynamicIslandμ UIλ μμμλ κ°λ¨νκ² μ΄ν΄λ΄€μ§λ§, ν¬κ² 3κ°μ§λ‘ ꡬμ±λλ€.
expand | compact | minimal |
---|---|---|
![]() |
![]() |
![]() |
λ¨Όμ , compact λͺ¨λμ λν΄μ μ΄ν΄λ³΄λ©΄, νμ±νλ λ€μ΄λλ―ΉμμΌλλκ° λ¨ νλμ μ±λ§ μλ κ²½μ°μ λ ΈμΆλλ λͺ¨λμ΄λ©° LeadingSide, TrailingSideμ UIλ₯Ό μ¬μ©ν μ μλ€.
struct TimerWIdgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TimerWIdgetAttributes.self) { context in
//
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
}
DynamicIslandExpandedRegion(.trailing) {
}
DynamicIslandExpandedRegion(.bottom) {
}
} compactLeading: {
// Compact λͺ¨λ Leading Side
} compactTrailing: {
// Compact λͺ¨λ Trailing Side
} minimal: {
}
}
}
}
μ΄μ΄μ νμ±ν λ λ€μ΄λλ―ΉμμΌλλκ° 2κ° μ΄μμ μ±μ΄ μλ κ²½μ°μ μ¬μ©λλ λͺ¨λμΈ minimalμ λν΄μ μ΄ν΄λ³΄μ.
minimal λͺ¨λμ attached, detachedμ μμμ UIλ₯Ό λ ΈμΆνκ² λλλ°, UIμ λν ꡬμ±μ compact λͺ¨λμ²λΌ λ³λλ‘ κ΅¬μ±ν΄μ£Όμ§ μμλ νλμ UIλ₯Ό μ¬μ©νκ² λλ€.
struct TimerWIdgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TimerWIdgetAttributes.self) { context in
//
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
}
DynamicIslandExpandedRegion(.trailing) {
}
DynamicIslandExpandedRegion(.bottom) {
}
} compactLeading: {
} compactTrailing: {
} minimal: {
// minimal λͺ¨λ
}
}
}
}
λ§μ§λ§μΌλ‘ expand λͺ¨λμ λν΄μ μ΄ν΄λ³΄λλ‘ νκ² λ€.
expandλͺ¨λλ νμ±νλ λ€μ΄λλ―ΉμμΌλλλ₯Ό κΈΈκ² ν°μΉ νμ λμ λ λ§μ μ 보λ₯Ό 보μ¬μ£ΌκΈ° μν΄ μ¬μ©λλ λͺ¨λμ΄λ€.
μ¬κΈ°μλ leading, trailing, bottom, center μ΄λ κ² 4κ°μ§μ μμμ ꡬμ±ν μ μλλ° κ° μμλ€μ μ΅μ λλ‘ νμλ μλμ§λ§ λ°λμ νλμ μμμ λν΄μλ μ½λλ₯Ό μ¬μ©ν΄ μ£Όμ΄μΌ νλ€.
struct TimerWIdgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TimerWIdgetAttributes.self) { context in
//
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
// expand λͺ¨λ leading μμ
}
DynamicIslandExpandedRegion(.trailing) {
// expand λͺ¨λ trailing μμ
}
DynamicIslandExpandedRegion(.bottom) {
// expand λͺ¨λ bottom μμ
}
DynamicIslandExpandedRegion(.center) {
// expand λͺ¨λ center μμ
}
} compactLeading: {
} compactTrailing: {
} minimal: {
}
}
}
}
λ€μ΄λλ―ΉμμΌλλ UIλ₯Ό μμ ν λμ λ°λμ κ³ λ €ν΄μΌ νλ λΆλΆμ΄ μλλ°, λ°λ‘ μ€λ²νλ‘μ°κ° λ°μνκ² λλ©΄ νμ±νκ° μλ μ μμΌλ μ΄ λΆλΆμ κ³ λ €ν΄ μ¬μ΄μ¦ κΈ°μ€μ λ§μΆ°μ€μΌ νλ€.
WidgetKitμ κΈ°λ₯ μ€ LiveActivityλ₯Ό μ¬μ©νμ¬ μ κΈνλ©΄κ³Ό λ€μ΄λλ―ΉμμΌλλμ UI μ¬μ© λ° μ μ΄ λ°©λ²μ λν΄μ μμλ΄€λ€.
μ΄λ² κΈμμ μ§μ μμ λ₯Ό μ¬μ©ν΄ LiveActivityλ₯Ό ꡬμ±νλ©΄μ κΈμ μμ±νλ €κ³ νμμ§λ§ κΈμ λ΄μ©μ΄ λ무 κΈΈμ΄μ Έμ λ³λλ‘ κΈμ μ¬λ¦¬λλ‘ νκ² λ€.
κ°μ¬ν©λλ€.