iyOmSd/Title: SwiftUI

[SwiftUI] Widget 위젯만들기

냄수 2021. 7. 6. 19:54
반응형

한번 만들어봐야지 생각만하고 해보지못했던 위젯을 드디어 만들어 보려고합니다~~

 

평소에 iOS프로젝트 생성하듯이 빈프로젝트를 만들고

Target을 선택하면

~~Extension이 많이보여요

그중에서 이번에 할 것은 위젯이니까

찾아서 클릭!

위젯이름 넣어주고

만들면

Active하겠냐고 묻는거 확인누르고!

이제 위젯이 만들어졌어요!

빌드하면 제가 방금만든 위젯이 보일거에요

 

위젯에는 3가지 요소가 중요해요

WidgetConfiguration: 위젯 식별 및 위젯의 Content표시

Provider: 시간에 따른 위젯 업데이트 로직

EntryView: 위젯을 표시하는 View

 

처음으로 구현되어있는 코드를보면

Widget코드!

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

    var body: some WidgetConfiguration {
        IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in
            NSWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("My Widget") // 위젯 설명 타이틀
        .description("This is an example widget.") // 위젯 설명 부타이틀
        .supportedFamilies([.systemSmall, .systemLarge]) // 위젯 크기 설정
    }
}

위젯의 타이틀과 부타이틀의 내용이 저기에 들어간다는걸 볼수 있어요

 

IntentConfiguration

사용자가 구성할 수 있는 속성이 있는 위젯

위젯에서 Edit를 통해서 위젯에 보여질 내용을 변경할 수 있음

 

StaticConfiguration

사용자가 구성할 수 있는 속성이 없는 위젯

정적인 데이터를 보여주기에 알맞은 타입의 위젯이에요

예) 일반적으로 주식시장 위젯이나 뉴스 헤드라인을 보여주는 위젯

 

생성자의 매개변수들을 하나씩 볼게요

kind: 위젯의 identifier

provider: 렌더링할 시기를 WidgetKit에 알려주는 타임라인을 생성함

클로져: SwiftUI 뷰를 포함. WidgetKit는 이를 호출하여 내용을 렌더링하고 provider로 부터 타임라인 엔트리 파라미터를 전달함

intent: 사용자가 구성할 수 있는 속성을 정의

 

 

다음으로 Provider을 알아볼게요

struct Provider: IntentTimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), configuration: ConfigurationIntent())
    }

	// 위젯 갤러리에서 보여질 부분
    func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date(), configuration: configuration)
        completion(entry)
    }
	// 정의한 타임라인에 맞게 업데이트해서 보여질 내용
    func getTimeline(for configuration: ConfigurationIntent, 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, configuration: configuration)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

placeholder: 특정 내용이 없는 시각적표현

getSnapshot: WidgetKit이 위젯이 일시적인 상황에 나타나면 호출하는 함수

Context.isPreivew가 참이면 위젯 갤러리에 위젯이 나타남

이경우 가능한 빨리 처리하기위해 위젯의 현재상태를 가져오거나 몇초이상 걸릴 수 있는경우 샘플 데이터를 제공함

위젯갤러리에서 위젯을 고를 때 보이는 샘플있죠? 그때 보이는 작업을 여기에 해주면되요

getTimeline: 현재 시간과 위젯을 업데이트할 향후 시간에 대한 타임라인 항목을 제공함

 

Timeline타입의 매개변수로 policy라는게있는데

TimelineReloadPolicy타입이구요

이 타입이 위젯에 새로운 타임라인을 제공해주는 시기를 지정할 수 있도록해줘요

.atEnd - 현재주어진 타임라인이 마지막일 때 새로 타임라인을 요청

.after - 해당 date후에 새로운 타임라인 요청

.never - 가능한 즉시 새로운 타임라인을 요청..?(A policy that specifies that the app prompts WidgetKit when a new timeline is available.)

 

위젯의 크기가 다양하게 있는걸 아시나요?!

@Environment(\.widgetFamily) var family: WidgetFamily

이코드를 통해서 위젯의 환경변수에 접근해서 작은위젯 중간위젯 큰위젯에 접근 할 수 있어요

또한 Entry타입에도 Context정보가 포함되어있어서 골라서 사용하면되요

 

마지막으로 위젯을 나타낼 뷰의 코드인 EntryView!

struct NSWidgetEntryView : View {
    @Environment(\.widgetFamily) var family: WidgetFamily
    var entry: Provider.Entry

    var body: some View {
        sizeBody()
    }
    
    @ViewBuilder
    func sizeBody() -> some View {
        switch family {
        case .systemSmall:
            VStack {
                Text("small")
                Text(entry.date, style: .time)
            }
        case .systemMedium:
            VStack {
                Text("medium")
                Text(entry.date, style: .time)
            }
        case .systemLarge:
            VStack {
                Text("large")
                Text(entry.date, style: .time)
            }
        default:
            EmptyView()
        }
    }
}

이렇게 크기에 따라서 만들어 줄 수 있죠

 

 

한앱에 여러개의 위젯을 만들고싶다면

@main
struct NSWidgetBundle: WidgetBundle {
    @WidgetBundleBuilder
    var body: some Widget {
        NSWidget()
        NSWidget()
    }
}

main을 새로만들어준 NSWidgetBundle로 변경하고 WidgetBundle을 구현해주면돼요

이렇게 코드를 작성한경우에는

NSWidget에는 현재 작은사이즈, 큰사이즈가 있으므로

2세트인 4개의 위젯이 보이겟네요

 

반응형