In my previous article, we talked about how we can protect our users’ privacy by redacting widget data. It’s a simple process, but unfortunately, there aren’t many options available when it comes to the redacted effect.
In this article, I’ll show you how you can create your own unique redacted effect. This will enhance the visual appeal of your widget when data is redacted and make it look more professional.
Moreover, there’s something you need to be aware of. I noticed a strange behavior in iOS 16 when applying custom redacted effects to a widget. Therefore, we’ll be discussing that as well and showing you how to work around it.
So, without further ado, let’s get started!
The Straightforward Way
Let’s use the Bitcoin wallet widget we created in my previous article and apply a blur effect on the balance value.
We can achieve this by using the redactionReasons
environment key in SwiftUI to determine the current redaction state of the view.
Once we have the current redaction state, we can apply the blur effect accordingly. Here’s how:
@Environment(\.redactionReasons) var reasons
var body: some View {
VStack(alignment: .leading) {
Text("Bitcoin Balance")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.orange)
if reasons.isEmpty {
// Show balance
Text("0.25₿")
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(.gray)
} else {
// Hide balance
Text("0.25₿")
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(.gray)
.blur(radius: 4)
}
}
}
While this approach is simple and effective, it unfortunately only works on iOS 15 and lower.
What do I mean? Let me show you.
The Strange Behavior on iOS 16
In iOS 16, Apple has introduced a new privacy setting that affects the accessibility of the Lock Screen widgets when the device is locked, causing the aforementioned approach unusable.
As mentioned in my previous article, turning on the setting causes the .privacySensitive()
modifier to stop working, and the same goes for the custom redacted effect. On the other hand, turning off the setting causes the entire widget to be redacted with the default redact style.
Now, here’s where it gets weird. Adding a privacy-sensitive UI element to the widget’s body suddenly causes everything to work as expected.
This feels really weird to me and seems like other fellow developers on Twitter and LinkedIn also feel the same too.
As of this writing (iOS 16.4), this odd behavior still exists. Hopefully, Apple will provide an official explanation in the near future.
Working Around the Strange Behavior
Based on what we just observed, the easiest workaround to this behavior is to add a privacy-sensitive Text
view with zero height in our widget.
@Environment(\.redactionReasons) var reasons
var body: some View {
ZStack {
// Zero height Text view
Text("---")
.privacySensitive()
.frame(maxWidth: .infinity, maxHeight: 0.0)
.clipped()
// Widget UI here
// ...
// ...
}
}
With the above workaround, we can maintain the original UI layout while achieving the desired custom redacted effect.
To make our code more readable and easier to use, we can create a View
extension.
extension View {
func customRedactActivate() -> some View {
ZStack {
Text("---")
.privacySensitive()
.frame(maxWidth: .infinity, maxHeight: 0.0)
.clipped()
self
}
}
}
With the View
extension in place, we can simply call customRedactActivate()
on any widget view like so:
VStack(alignment: .leading) {
Text("Bitcoin Balance")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.orange)
if reasons.isEmpty {
// Show balance
Text("0.25₿")
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(.gray)
} else {
// Hide balance
Text("0.25₿")
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(.gray)
.blur(radius: 4)
}
}
.customRedactActivate()
Doing so not only increases the reusability of our code but also makes our code more concise and easier to understand.
Further Readings
- How to Update or Refresh a Widget?
- How to Fetch and Show Remote Data on a Widget?
- How to Create Configurable Widgets With Static Options?
- How to Create Configurable Widgets With Dynamic Options?
- How to Handle Tap Gestures on Widgets?
What are your thoughts on the strange behavior? Do you have any suggestions for a better workaround? Don’t hesitate to reach out to me on Twitter or LinkedIn to share your ideas.
Also, make sure to follow me on Twitter or LinkedIn and subscribe to my newsletter to stay up-to-date with my latest iOS development-related articles.
Thanks for reading! 👨🏻💻
👋🏻 Hey!
While you’re still here, why not check out some of my favorite Mac tools on Setapp? They will definitely help improve your day-to-day productivity. Additionally, doing so will also help support my work.
- ✨ Bartender: Superpower your menu bar and take full control over your menu bar items.
- ✨ CleanShot X: The best screen capture app I’ve ever used.
- ✨ PixelSnap: Measure on-screen elements with ease and precision.
- ✨ iStat Menus: Track CPU, GPU, sensors, and more, all in one convenient tool.