Make a placeholder view in SwiftUI with redacted()
Table of Contents
In iOS 14, SwiftUI has a new modifier to redact any content. You apply it to any view with a new view modifier, redacted(reason:)
. This modifier required a reason modifier, which tells SwiftUI the reason for this redaction. Right now, Apple provides only one reason, .placeholder
.
Here’s how it looks:
Text("Hello, SwiftUI!")
.redacted(reason: .placeholder)
As the name implies, placeholder reason redact content in a way to be used as a placeholder before the actual content is loaded.
Since Apple design RedactionReasons
as an option set, I expected more reason that we can use and combine in the future. Something like .sensitive
reason with pixelation effect or .animated
which produce a shimmering effect would be a nice add up.
public struct RedactionReasons : OptionSet
Complex View
Redaction reasons pass along to all child views. That's mean you can call it on a parent view, and all subviews would get the same reasons.
struct LandmarkView: View {
var body: some View {
VStack(alignment: .leading) {
Image("bigsur")
.resizable()
.frame(width: 100, height: 100)
.clipShape(Circle())
Text("Big Sur \(Image(systemName: "sun.dust"))")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.blue)
Text("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy").font(.body)
Button("Bookmark", action: {
print("Bookmark")
})
}
.padding()
}
}
Calling .redacted
on LandmarkView
would redact all of its subviews.
LandmarkView().redacted(reason: .placeholder)
You can easily support sarunw.com by checking out this sponsor.
Offline Transcription: Fast, privacy-focus way to transcribe audio, video, and podcast files. No data leaves your Mac.
Opt-out
If you don't want some view to be redacted, you can opt-out by using .unredacted()
which removes any redaction reason that is applied to the view.
Text("Big Sur \(Image(systemName: "sun.dust"))")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.blue)
.unredacted()
Add .unredacted()
to Text
will produce the following result:
Caveats
At current Xcode beta (beta 6), redact a view only changes its appearance, but it can still receive user interaction. If you have a redacted button, beware that the button can still receive user action.
Redaction-aware view
We can make our view redaction-aware and respond to the redaction reason by observing the value in @Environment(\.redactionReasons)
.
In the following example, we modify our LandmarkView to show SF Symbols image over the Big Sur image if a redaction reason is presented.
struct LandmarkView: View {
@Environment(\.redactionReasons) private var reasons // 1
var body: some View {
VStack(alignment: .leading) {
if reasons.isEmpty { // 2
Image("bigsur")
.resizable()
.frame(width: 100, height: 100)
.clipShape(Circle())
} else {
Image("bigsur")
.resizable()
.frame(width: 100, height: 100)
.clipShape(Circle())
.overlay( // 3
Image(systemName: "photo")
.font(.system(size: 34, weight: .bold))
.foregroundColor(.white)
.unredacted())
}
Text("Big Sur \(Image(systemName: "sun.dust"))")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.blue)
.unredacted()
Text("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy").font(.body)
Button("Bookmark", action: {
print("Bookmark")
})
}
.padding()
}
}
<1> We add @Environment(\.redactionReasons)
for our view to read redaction reason and act accordingly.
<2> If the reason is not set (reasons.isEmpty
), we show the image as is.
<3> If the reason is set (.redacted
is applied), we show SF Symbols over our redacted image.
We can also tackle the button problem by disabling it if the view is being redacted.
Button("Bookmark", action: {
print("Bookmark")
}).disabled(!reasons.isEmpty)
Conclusion
Tips and tricks in this article should be enough for you to work around limitations you encounter with redaction API. Even though we only have a redaction reason right now, I think Apple will support more variation in this API's rendering effect in the future, and I'm looking forward to it.
You can easily support sarunw.com by checking out this sponsor.
Offline Transcription: Fast, privacy-focus way to transcribe audio, video, and podcast files. No data leaves your Mac.
Related Resources
Read more article about SwiftUI or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareMove your view around with Drag Gesture in SwiftUI
SwiftUI's UIPanGestureRecognizer equivalent.
Testing delegates and protocols in XCTest
Learn how to write unit tests for delegate/protocol methods.