Adjusting Your App's Widgets to Use .containerBackground(for:)

If you're using widgets and you want them to run on all of Apple's new platforms, you're going to need to use this modifier.

The .containerBackground(for:) modifier

This year's round of Apple platform updates finally allows widgets to be shown across the ecosystem. Now widgets can be used on iPadOS 17 and on macOS Sonoma. This is dope, but to handle all of these different contexts elegantly, our widget code needs to be updated to use the .containerBackground(for:) modifier.

This handy little whipper-snapper helps the various platforms decide how to render our our widget's backgrounds in different scenarios. Without it, the new platforms and contexts might render widgets that aren't legible or simply aren't what we're intending.

By using this modifier, all of Apple's platforms know exactly which bits are considered background, and which bits are the foreground. When our widgets are being rendered on an iPhone or iPad Lock Screen, the background can simply be dropped to increase contrast and let those vibrant wallpapers tint our content. When shown in full-color on macOS, or even on WatchOS, the backgound we define in .containerBackground(for:) will be rendered.

How I figured this out

Monday night, when Xcode 15 and iOS 17 finally finished downloading to my Mac, I rushed to build my app (NextGP) to see how it fared on the new OS. Most of the app functioned and looked great with one glaring exception: Lock Screen Widgets.

All of my widgets were showing this strange stop sign icon with an exclamation point and some some truncated text: "WIDGET_BAC..." When I went back to Xcode to preview my widgets, I saw this warning: "Widget needs to adopt container background."

Clicking that tiny little "i" icon game me a few more details:

As soon as I added the .containerBackground(for:) modifier, this problem went away. In my case, I'm not yet shipping to any other platforms other than iOS, so I just kept it simple. Here is some sample code.

struct MyWidgetAccessoryRectangular: View {
    var body: some View {
        ZStack  {
            ...
        }
        .containerBackground(for: .widget) {
            Color.white
        }
    }
}

Now when I build and run, my widgets render how I expect them to. The fact that it started raining while I was figuring this out was pure coincidence, I'm sure. 😎

References

Follow me on Mastodon, Twitter, Instagram

Subscribe to Optimistic Closures

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe