위젯은 날씨 또는 지도와 같이 기본적으로 많이 사용되는 기능으로 WidgetKit 으로 구현할 수 있습니다
WidgetKit 은 iOS 뿐만 아니라 watchOS, iPadOS 등 모든 곳에서 사용될 수 있습니다.
Widget 이란?
위젯은 미니 앱이 아니다
위젯은 최소 앱 아이콘 4개 크기인 작은 크기로 구현됩니다.
위젯은 사용자가 집중해서 이해하려할 정도로 복잡하게 구현하면 실패합니다. 내용은 최대한 간결하게 만들어야 합니다.
WidgetKit 작동 원리
WidgetKit extension 는 타임라인에 따라 반환되는 뷰 계층인 백그라운드 extension 입니다.
즉 WidgetKit 을 사용하면 시간대 별로 뷰가 만들어져 계층을 이루어 시간에 맞게 화면에 보여줍니다.
예를 들어 캘린더의 시간대별로 사용자한테 제공해야 하는 View 들을 만들어 순서대로 사용자한테 제공해줍니다.
만약 사용자가 캘린더의 내용을 바꾸게 된다면 캘린더는 API 를 통해 타임라인을 다시 알맞게 WidgetKit extension 이 뷰계층을 업데이트합니다.
위젯에는 Kind, configurtion, supportedFamilies, placeholder
Widget Configuration (위젯 구성)
위젯은 2 종류의 configuration 이 존재합니다.
- Static Configuration
- Intent Configuration
Static Configuration (정적)
Static Configuration 은 사용자가 위젯에 포함될 내용을 설정할 필요가 없습니다. 앱에서 정해진 내용을 그대로 사용자한테 제공만 하면 되기 때문에 정적(Static) Configuration 이라고 부릅니다.
Intent Configuration (동적)
Intent Configuration 은 사용자의 의도(Intent) 에 따라 구성할 수 있습니다.
사용자가 의도한 내용을 보여줄 수 있는 아래 알림 앱이 대표적인 의도(Intent) Configuration 을 사용한 예시입니다.
SupportedFamilies (위젯 크기)
위젯은 3가지 종류의 크기가 존재하며 3개를 한꺼번에 supportedFamilies 라고 부릅니다. 즉 지원되는 가족들(크기들) 로 해석 가능
- systemSmall
- systemMedium
- systemLarge
Placeholder UI (위젯의 기본 내용)
모든 종류의 위젯은 PlaceholderUI 를 제공해야 합니다. Placeholder UI 는 위젯의 기본 콘텐츠를 의미합니다.
- Placeholder UI 는 어떠한 데이터도 존재하면 안됩니다.
- Placeholder UI는 매우 드물게 호출되며, 언제 호출될지 보장할 수 없습니다.
- 전형적으로 dynamic type 설정이 변경되는 것처럼 기기의 환경이 변경되었을 때 새로운 plceholder UI 를 부릅니다.
- 좋은 Placeholder UI 는 사용자가 이 위젯이 어떤 위젯인지 잘 파악할 수 있도록 만든 것 입니다.
@main
public struct SampleWidget: Widget {
private let kind: String = "SampleWidget"
public var body: some WidgetConfiguration {
StaticConfiguration(kind: kind,
provider: Provider(),
placeholder: PlaceholderView()) { entry in
SampleWidgetEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
코드를 봤을 때 StaticConfiguration 에는 placeholder 를 넣을 수 있는 파라미터 값이 존재합니다.
StatelessUI
- 위젯은 미니앱이 아니기 때문에 스크롤링이 되지 않습니다
- 스위치와 다른 시스템 컨트롤이 불가능합니다
- 비디오나 애니매이션 기능이 있는 사진도 불가능합니다
Deek link (탭해서 열기)
음악 앱처럼 위젯에 존재하는 음악을 탭하면 해당 앱으로 연결 (딥 링크) 됩니다.
음악 앱은 또한 systemMedium 또한 지원하는데 이는 각 노래에 맞게 딥 링크 됩니다.
뿐만 아니라 전체 위젯은 URL API 를 사용하여 URL 링크와 연결할 수 있습니다.
systemMedium 또는 systemLarge에서 하위 링크를 만들고 싶다면 SwiftUI 의 새로운 Link API 를 사용하면 됩니다.
Views
위젯을 만들면서 신경 써야할 View 는 위와 같이 3가지 View 가 있습니다
Snapshot
Snapshot 이란 위젯의 상태나 데이터를 미리보기 형식으로 나타낸 것을 의미합니다. 즉 앱이 백그라운드에 있거나 위젯이 업데이트를 받을 수 없는 상황에서도 사용자에게 즉시 보여줄 수 있는 위젯의 미리 준비된 상태를 제공합니다.
Timeline (타임라인)
타임라인은 위젯이 어떤 시간에 어떤 뷰를 보여줄지 결정하는 것입니다.
- Entry 란 위젯에 표시할 하나의 데이터 조각을 말합니다. 각 Entry는 특정 시점에 해당하는 데이터를 나타냅니다.
예를 들어, 날씨 위젯의 경우 특정 시간대의 날씨 정보를 담고 있는 것을 하나의 Entry 라고 합니다. - Timeline 은 특정 시점을 연관시킵니다. 각 Entry는 언제 위젯이 표시되어야 할지를 결정하는 시간을 포함합니다.
- Timeline 은 시간에 따라 다양한 Entry 를 순차적으로 표시하며, 이를 통해 여러 정보를 제공할 수 있습니다.
- Timeline 은 다크모드와 라이트모드를 반드시 지원 해야합니다.
Timeline 예시 코드
TimelineProvider라는 프로토콜은 위와 같이 구성되어 있습니다.
1. Entry: Timeline Entry로 주로 date 정보가 담고 있습니다.
2. Context: 환경(environment) 정보와 시스템이 어떤 entry들을 요청하는지를 담고 있습니다.
3. snapshot function: system이 요구하는 single entry 입니다.
4. timeline function: system이 entry들의 series를 요청합니다.
public struct Provider: TimelineProvider {
public func snapshot(with context: Context,
completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
public func timeline(with context: Context,
completion: @escaping (Timeline<Entry>) -> ()) {
let entry = SimpleEntry(date: Date())
let timeline = Timeline(entries: [entry, entry], policy: .atEnd)
completion(timeline)
}
}
Reloads (위젯 업데이트)
Reloads 는 Timeline 에서 시간에 따라 내용이 바뀌는 것을 의미합니다.
시스템은 WidgetKit extension 을 깨워 새로운 timeline 들을 요구합니다.
이렇게 system 에 의해 각 timeline 의 entry 들은 모두 내용을 최신 데이터로 유지하여 정확한 정보를 사용자한테 제공합니다.
Reload Policy (리로드 정책)
타임라인이 끝날 때, 특정 시간이 지났을 때, 혹은 시스템에 의해 강제적으로 리로드가 발생합니다. 시스템은 위젯이 자주 보이는 경우 더 자주 리로드를 요청하고, 자주 보이지 않는 경우 리로드 빈도를 줄입니다. 이를 통해 시스템은 효율적으로 리소스를 관리합니다.
- atEnd
- after(date: Date)
- never
기기의 환경이 변경되면(예: 시간대 변경) 시스템이 위젯을 강제로 리로드할 수 있습니다. 또는 앱에서 알림을 받거나 사용자가 앱에서 변경사항을 만들었을 때도 위젯 리로드를 요청할 수 있습니다.
WidgetCenter API
- WidgetCenter API는 앱에서 데이터를 변경시킬 경우 타임라인을 리로드 해줍니다. 앱이나 위젯 확장에서 호출할 수 있으며, 특정 종류의 위젯만 리로드하거나, 모든 종류의 위젯을 리로드할 수 있습니다.
특정 Timeline 을 리로드하는 reloadTimelines(ofKind:) 또는 모든 Timeline 을 리로드하는 reloadAllTiemlines 가 존재합니다.
추가로 getCurrentConfigurations 메서드를 통해서 현재 구성하고 있는 모든 configuration 들을 리스트로 받아올 수 있습니다.
- Background URLSession: 서버에서 데이터를 받아와야 할 때는 백그라운드 URL 세션을 통해 작업을 시작할 수 있고, 데이터는 위젯 확장으로 전달됩니다.
효율적인 리소스 사용
위젯을 리로드하려면 효율적으로 진행해야 합니다. 각각의 Relaod는 여러 방식으로 구현될 수 있으며 신중해야 합니다.
- 위젯은 매초 업데이트되는 라이브 앱이 아니므로 네트워킹과 프로세싱을 최소화하여 효율적으로 작동해야 합니다. 네트워크 요청은 배치하여 사용하고, 필요 이상으로 많은 리소스를 소모하지 않도록 신경 써야 합니다.
사용자 맞춤형 위젯
- Intents Framework: 사용자가 위젯을 구성할 수 있도록 도와주는 강력한 도구입니다. 위젯의 설정(예: 주식 앱에서 보여줄 주식 선택)은 Intents를 통해 사용자에게 질문을 하고, 그 답에 따라 타임라인을 설정할 수 있습니다.
- Intents Dynamic Options: 사용자는 위젯 구성 UI에서 검색을 통해 선택 항목을 추가할 수 있으며, 이때 인텐트가 동적으로 검색 결과를 반환하여 위젯에 반영할 수 있습니다.
지능형 스택과 관련성 (Relevance)
- iOS에서는 여러 위젯을 스택에 쌓아둔 후, 가장 관련성 있는 위젯을 자동으로 보여줄 수 있습니다. 이를 위해 위젯이 관련성 점수와 지속 시간을 지정할 수 있는 TimelineEntryRelevance API를 제공합니다.
- Shortcuts 및 인텐트를 통해 사용자가 특정 작업을 수행할 때 관련성 높은 위젯이 스택에서 자동으로 회전되어 나타날 수 있습니다. 이를 통해 더 직관적인 사용자 경험을 제공합니다.
위젯의 설계 철학
- 위젯은 작은 미니 앱이 아니라, 짧은 시간 안에 유용한 정보를 제공하는 한눈에 볼 수 있는 경험을 제공해야 합니다.
- 타임라인과 리로드 정책을 적절히 사용하고, 시스템의 지능형 스택 기능을 활용하여 사용자에게 최적의 경험을 제공하는 것이 중요합니다.
'SwiftUI' 카테고리의 다른 글
SwiftUI - 드래드 기능 On Off 할 수 있게 만들기 (0) | 2024.10.11 |
---|---|
프로그래머스 - 최댓값과 최솟값 (0) | 2024.10.10 |
WidgetKit - 위젯 만들기 전에 알아둘 것들 (10) | 2024.10.07 |
WWDC24 Translation API (번역 API) (3) | 2024.10.05 |
WWDC20 Data Enssentials in SwiftUI (EnvironmentObject, ObservableObject, ObservedObject, StateObject, AppStorage, SceneStorage, 생명주기) (1) | 2024.10.03 |