본문 바로가기
iOS - 실무관련/iOS

WidgetKit에 대한 간단한 설명

by print_soo 2022. 9. 13.
// 참고 URL: https://zeddios.tistory.com/1088?category=796110

import WidgetKit
import SwiftUI

// TimelineProvider: Widget의 디스플레이를 업데이트 할 시기를 WidgetKit에 알려주는 타입

struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date())
        
    }

    // 현재 상태를 나타내는 스냅샷을 가져오는 메소드
    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date())
        completion(entry)
    }

    // 현재 상태와 Widget상태가 변경 될 미래 날짜가 포함된 타임라인 엔트리 배열을 가져오는 메소드
    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
            let entry = SimpleEntry(date: entryDate)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
    
    /*
     
     [TimelineProviderContext]
     
     - isPreview: 위젯 갤러리에서 위젯 미리보기일 때를 알아낼 때 사용
     
     - family: widget의 size type
     
     - displaySize: widget의 point size
     
     - environmnetVariantes: Widget이 표시될때 설정될 수 있는 모든 environmnet values (ex. colorSchme, displayScale)
     
     */
    
}

//MARK: - Widget rendering Setting

struct SimpleEntry: TimelineEntry {
    let date: Date // WidgetKit이 Widget을 렌더링할 date
}

//MARK: - Widget Content View Setting
struct Tutorial_WidgetEntryView : View {
    var entry: Provider.Entry
    
    var body: some View {
            Text(entry.date, style: .time)
    }
}

/*
 EntryView에서는 WidgetFamily에 따라서 분기 처리해서 대응이 가능하다.
 
 @Environment(\.widgetFamily) var widgetFamily
 
 switch widgetFamily {
 case .systemSmall:
     Text("작은 놈")
 case .systemMedium:
     Text("애매한 놈")
 case .systemLarge:
     Text("큰 놈")
 default:
     Text("모르는 놈")
 }
 
 */

//MARK: - Widget System Setting

@main
struct Tutorial_Widget: Widget {
    let kind: String = "Tutorial_Widget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            Tutorial_WidgetEntryView(entry: entry)
        }
        .configurationDisplayName("위젯를 배우자.") //
        .description("위젯기능은 좋은거 같아요.") // 위젯 추가 시에 뜨는 SubTitle
        .supportedFamilies([.systemSmall, .systemMedium, .systemLarge]) // 지원하는 위젯의 크기
    }
    
    /*
     - kind: 위젯을 식별하는 문자열 (식별하는 용도이기 때문에 Bundle Identifier를 사용하면 좋음)
     
     - provider: TimlineProvider를 준수하고 위젯을 렌더링할 때 WidgetKit에 알려주는 타임라인을 생성하는 개체 (쉽게 말하자면, 위젯을 새로고침할 타임라인을 결정하는 객체)
     
     - configurationDisplayName: Widget Title
     
     - description: Widget 설명
     
     - supportedFamilies: 지원하는 Widget Size
     
     - Content(Closure 내부): WidgetKit이 Widget을 렌더링하는데 필욯란 SwiftUI View가 포함되어 있다. + 이 Closure를 호출할 때 WidgetKit은 Widget Provider의 getSnapshot(in:completion:) 또는 getTimeline(in:completion:) 메소드로 타임라인 항목들을 전달한다.
    */
}

//MARK: - WidgetPreviewer

struct Tutorial_Widget_Previews: PreviewProvider {
    static var previews: some View {
        Tutorial_WidgetEntryView(entry: SimpleEntry(date: Date()))
            .previewContext(WidgetPreviewContext(family: .systemMedium))
    }
}