• Complication timeline

    • WatchOS 2: ClockKit으로 서드파티 Complication을 만들 수 있게 됨
    • WatchOS 5: 그래픽 컨텐츠 지원 및 다양한 크기의 complications 추가
    • WatchOS 7: SwiftUI 지원, 다중 complications 지원
    • WatchOS 9(현재): WidgetKit으로 Complication을 만들고, 코드를 iOS와 공유할 수 있게 됨
  • new API

    • 새로운 WidgetFamily - accessory 접두사가 붙음

      public enum WidgetFamily {
      	...
      	case accessoryCircular
      	case accessoryRectangular
      	case accessoryInline
      	
      	// watchOS 전용
      	case accessoryCorner
      }
      
      • accessoryRectangular: 여러 줄의 텍스트와 그래픽, 차트 등을 보여주기 위함. ClockKit의 graphicRectangular와 해당

        스크린샷 2022-06-10 오후 10.27.52.png

      • accessoryCircular: 간단한 정보, 게이지, 프로그레스 등을 보여주는데 적합. ClockKit의 graphicCircular에 해당

        스크린샷 2022-06-10 오후 10.34.09.png

      • accessoryInline: 텍스트만 들어갈 수 있는 영역. WatchOS에서는 여러군데에, iOS에서는 시간 위에 배치 가능. 기존에는 없던 family

        스크린샷 2022-06-10 오후 10.38.01.png

      • accessoryCorner: 작은 원형 위젯 + 게이지 및 텍스트. 이번 세션에서는 공통된 family만 다루기 때문에 해당 패밀리는 다른 세션(Go Further with WidgetKit complications)에서 다룸

        스크린샷 2022-06-10 오후 10.39.42.png

  • Colors

    • 제공되는 렌더링 모드

      public struct WidgetRenderingMode {
      	static var fullColor: WidgetRenderingMode
      	static var accented: WidgetRenderingMode
      	static var vibrant: WidgetRenderingMode
      }
      
      struct MyWidgetView: View {
      	@Environment(\\.widgetRenderingMode) var renderingMode
      
      	var body: some View {
      		switch renderingMode {
      			// ...
      		}
      	}
      }
      
      • Full Color(WatchOS): 명시된 대로 보임

      • accented(WatchOS): 뷰가 두개의 컬러 그룹으로 나뉘고, 이 그룹별로 플랫하게 색이 입혀짐. 원래 뷰의 opacity만 유지된다.

        • widgetAccentable() modifier로 그룹을 지정하거나, 렌더링 모드에 따라서 분기 시키는 방식으로 구분한다.

          VStack(alignment: .leading) {
              Text("Headline")
                  .font(.headline)
                  .widgetAccentable()
              Text("Body 1")
              Text("Body 2")
          }.frame(maxWidth: .infinity, alignment: .leading)
          
      • vibrant(iOS 잠금화면): 색채가 다 빠지고, 잠금화면에 맞게 색이 지정된다.(grayscale값을 참조해서, 뒤 컨텐츠에 맞게 조정된다.)

        • 회색조 뿐 아니라 틴트를 주도록 설정할 수도 있다. 이 때는 밝은 색일수록 더 불투명하고 명도가 높아진다.

        • 투명한 색상을 쓰면 배경에 가려질 수 있기 때문에 덜 중요한 컨텐츠는 어두운 색상으로 표현할 것

          ZStack {
               AccessoryWidgetBackground() // 일관적인 위젯 배경을 위해 미리 제공하는 프리셋
               VStack {
                  Text("MON")
                  Text("6")
                   .font(.title)
              }
          }
          
        • AccessoryWidgetBackground

          스크린샷 2022-06-10 오후 11.23.03.png

  • Project setup

    • watchOS용 화면을 만들려면, Widget 타겟을 watchOS로 지정하면 된다.

    • system 접두사가 붙은 위젯은 watchOS에서 지원하지 않기 때문에 코드를 공유하는 경우 분기가 필요하다.

    • iOS는 Intent를 Widget 편집 UI에서 설정할 수 있지만, watchOS에서는 프리셋을 만들어줘야 한다.

      func recommandations() -> 
      	[IntentRecommendation<DynamicCharacterSelectionIntent>] {
      	return recommendedIntents()
                  .map { intent in
                      return IntentRecommendation(intent: intent, description: intent.hero!.displayString)
                  }
      }
      
  • Making glanceable views

    • 기존 홈스크린 위젯보다 크기가 작기 때문에 이를 고려해야한다.
      • accessoryCircular예시

        ProgressView(interval: entry.character.injuryDate...entry.character.fullHealthDate,
                                 countdown: false,
                                 label: { Text(entry.character.name) },
                                 currentValueLabel: {
                        Avatar(character: entry.character, includeBackground: false)
                    })
                    .progressViewStyle(.circular)
        
      • accessoryRectangular 예시

        HStack(alignment: .center, spacing: 0) {
        	VStack(alignment: .leading) {
        		Text(entry.character.name)
        			.font(.headline)
        			.widgetAccentable()
        	
        		Text("Level \\(entry.character.level)")
        		Text(entry.character.fullHealthDate. style: .timer)
        	}.frame(maxWidth: .infinity, alighment: .leading)
        
        	Avatar(character: entry.character, includeBackground: false)
        }
        
        • 기본 폰트 스타일로 지정하는 것을 권장. 다른 위젯과 같이 놓았을 때 자연스럽게 하기 위해서.

          스크린샷 2022-06-10 오후 11.39.15.png

      • accessoryInline 예시 - 텍스트 및 이미지(옵션)

        • 지정된 컬러와 폰트로만 그려진다.

        • 이 때 ViewThatFits로 하면, 사이즈에 맞는 뷰를 자동으로 선택해준다.

          ViewThatFits {
              Text("\\(entry.character.name) is resting, combat-ready in \\(entry.character.fullHealthDate, style: .relative)")
              Text("\\(entry.character.name) ready in \\(entry.character.fullHealthDate, style: .timer)")
              Text("\\(entry.character.avatar) \\(entry.character.fullHealthDate, style: .timer)")
          }
          
  • privacy

    • low luminance: always on display 상태를 의미. 이 때는 밝기도 줄어들고 갱신 빈도도 낮아진다.

      스크린샷 2022-06-10 오후 11.46.26.png

    • low luminance 상태 확인

      @Environment(\\.isLuminanceReduced)
      var isLuminanceReduced
      
      var body: some View {
          if isLuminanceReduced {
              Text("🙈").font(.title)
          } else {
              Text("🐵").font(.title)
          }
      }
      
    • 잠금 상태 대응

      • 기본적으로는 placeholder뷰의 redacted 버전을 보여준다.
      • 일부만 가리려고 한다면 이를 지정하면 된다.
      VStack(spacing: -2) {
          Image(systemName: "heart")
              .font(.caption.bold())
              .widgetAccentable()
          Text("\\(currentHeartRate)")
              .font(.title)
              .privacySensitive()
      }