카테고리 없음

[SwiftUI] Intent Widget 동적 위젯 만들기

냄수 2023. 1. 1. 15:23
반응형

위젯은 만들때 두가지 형태로 만들수있어요

static형식과 intent형식이 있죠

 

2021.07.06 - [iyOmSd/Title: SwiftUI] - [SwiftUI] Widget 위젯만들기

이름에서도 느껴지듯 static은 그냥 보여주기만하는 정적인 위젯이에요

위젯 타임라인에 의해서 일정주기로 업데이트되거나 특정API로 위젯을 새로고침해서

보여주는 방식이죠

 

하지만 오늘 해볼것은

intent 형식이에요

intent형식은 위젯에 동적으로 값을 선택할 수 있고

사용자와 상호작용이 가능한 특성이 있어요

intent 체크박스를 클릭하면 intent형식의 위젯을 생성할 수 있어요

 

static과는 다르게

.intentdefinition파일이 생성되는걸 볼 수 있어요

위젯설정파일 같은곳인데

여기서 필요한 파라미터를 설정할 수 있어요

string, bool, 사용자정의 enum값 등등 원하는 값으로 설정할 수 있어요

위젯을 롱클릭하면 뜨는 저런 설정창에 보이게하려면

 

프로퍼티를 추가하고 프로퍼티속성에

Configurable에 있는 user can edit value in shortcuts, widgets 체크박스를 설정해야

롱클릭시 위젯에대한 프로퍼티를 수정 할수 있도록 보여줘요

 

이렇게 추가한 속성들을 컨트롤해야 동적으로 위젯을 설정할 수 있겟죠?

handler와 관련된 클래스는 엑스코드에서 자동으로 생성돼요

처음으로 위젯을 생성하면 Configuration이라는 이름으로 생성되고 이름을 변경할 수 있어요

(Configuration이름)Intent 형식으로 생성돼있어요

 

위젯에서 정의한 프로퍼티에 접근할때는

기본구현함수에 있는 configuration에 접근해서 해당 프로퍼티를 읽으면 사용할 수 있어요

 

Intent Handler 정의하기

추가적인 기능처리를위해서 IntentHandler를 새로 추가할수 있어요

widget을 생성하듯이

file > new > target에서

intents extension을 생성해주세요

새로운 디랙토리와 함께

INExtension를 상속받은 클래스가 생성될거에요 

위젯설정파일에서 방금추가한 handler타겟을 추가해주세요

 

handler는 동적인 옵션을 처리할 때 유용하게 사용할 수 있어요

Dynamic Options에 체크표시를하면 사용할 수 있어요

모든 타입에서 사용할 순 없고 옵션이 가능한 타입에서만 가능해요

Dynamic Options에 체크표시하면

IntentHandling프로토콜에 해당 프로퍼티를 동적으로 컨트롤할 수 있도록 함수가 자동으로 생성되요

IntentHandling프로토콜은

건든게없다면 디폴트는 ConfigurationIntentHandling 이거일거에요

위에서 정의한 (Configuration의 이름)IntentHandling 타입으로 생성되요

 

testArray라는 이름이라면

provideTestArrayOptionsCollection 이렇게 함수가 생성되네요

class IntentHandler: INExtension, ConfigurationIntentHandling {
    
    override func handler(for intent: INIntent) -> Any {
        // This is the default implementation.  If you want different objects to handle different intents,
        // you can override this and return the handler you want for that particular intent.
        
        return self
    }
    
    func provideTestArrayOptionsCollection(for intent: ConfigurationIntent) async throws -> INObjectCollection<NSString> {
        var items: [NSString] = []
        
        items.append("1")
        items.append("12")
        items.append("123")
        items.append("1234")
        return INObjectCollection(items: items)
    }
}

이렇게 아이템 혹은 섹션을 이용한 아이템을 만들어주면

위젯에서 이렇게 리스트형식으로 사용할 수 있어요

 

 

업데이트 시점

Intent 위젯의 업데이트 시점은

getTimeline에 정의한 시간간격 혹은 Intent가 프로퍼티가 변경되는 시점에 위젯이 업데이트되요

 

 

 

예시 

앞서 만든 위젯설정을 적용하기위해 간단한 예시를 만들어볼까요

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 1 ..< 10 {
            let entryDate = Calendar.current.date(byAdding: .second, value: hourOffset * 30, to: currentDate)!
            let entry = SimpleEntry(date: entryDate, configuration: configuration)
            entries.append(entry)
        }

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

위젯을 건들지않는다면 30초간격으로 업데이트가 일어나도록 해놨어요

 

struct LockScreenWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        ZStack {
            selectedColor(with: entry.configuration)
            VStack(alignment: .leading) {
                Text("time: \(timeString(entry.date))")
                Text("selected:\n\(entry.configuration.testSelected ?? 0)")
                Text("enum:\n \(selectedColorString(with: entry.configuration))")
            }
        }
    }
    
    private func timeString(_ date: Date) -> String {
        let format = DateFormatter()
        format.dateFormat = "mm:ss"
        return format.string(from: date)
    }
    
    private func selectedColor(with configuration: ConfigurationIntent) -> Color {
        switch configuration.testEnum {
        case .red: return .red
        case .blue: return .blue
        case .orange: return .orange
        default: return .white
        }
    }
    
    private func selectedColorString(with configuration: ConfigurationIntent) -> String {
        switch configuration.testEnum {
        case .red: return "빨강"
        case .blue: return "파랑"
        case .orange: return "주황"
        default: return ""
        }
    }
}

간단하게 위젯의 속성

업데이트된 시점을보기위해 시간이 분:초 가 써있고

selected의 값을보여주고

enum타입으로 컬러를 선택한 결과에맞게 위젯색을 변경하는거에요

 

 

위에서 위젯을 건들지않는다면 30초간격으로 업데이트가 일어나도록 했지만

속성을 건든다면 바로 위젯이 업데이트되서

분초가 바뀌는걸 볼 수 있을거에요

 

반응형