watchos

How can one write a WatchOS widget for accessoryCorner family that renders appropriately?


I'm trying to build a widget that has a gauge like in the image attached. It does not seem like there are any APIs to render the gauge (or any other view for that matter) on an arc, depending on which corner is used.

Screenshoot

Is there any such support, or are such widgets only available to Apple? E.g. can one tell which corner the widget is being rendered in, so that the correct transformations be computed?

Thank you!


Solution

  • You can get close to an Apple style corner widget, but there are currently some limitations. As far as I know you have to use the .widgetLabel modifier which restricts you to an "Image, Text, Gauge, ProgressView, or a container with multiple subviews".

    The styling for the Gauge and ProgressView seem to be predefined as well - for example styling the gauge with .gaugeStyle(LinearCapacityGaugeStyle()) doesn't change the appearance.

    var body: some View {
          switch widgetFamily {
          case .accessoryCorner: // WatchOS only
             Text("50%") // Watch out for clipping
                .font(.system(size: 20))
                .foregroundColor(.blue)
                .widgetLabel {
                   ProgressView(value: 0.5)
                      .tint(.blue)
                }
          }
    }
    

    or

    var body: some View {
          switch widgetFamily {
          case .accessoryCorner: // WatchOS only
             Text("50%") // Watch out for clipping
                .font(.system(size: 20))
                .foregroundColor(.blue)
                .widgetLabel {
                   Gauge(value: 50.0, in: 0...100) {
                      Text("Not shown")
                   } currentValueLabel: {
                      Text("Not shown")
                   } minimumValueLabel: {
                      Text("0") // Watch out for clipping
                   } maximumValueLabel: {
                      Text("100") // Watch out for clipping
                   }
                   .tint(.blue)
                   .gaugeStyle(LinearCapacityGaugeStyle()) // Doesn't do anything
                }
    

    Gives you:

    enter image description here enter image description here

    You can rotate the text manually to try and make it line up with corner, but as you say then there doesn't seem to be a way to identify which corner the widget is in so you don't know which way to rotate it...