Greetings, traveler!
Sometimes, we must prevent users from screen recording or taking screenshots. This is not a big deal for both UIKit and SwiftUI. Let’s delve into this topic a bit.
UIView extension
Spoiler: we will use the UIKit tools to create both solutions. So, it’s time to write an extension for UIView
.
The key tool will be a UITextField
, which can hide its content from capturing. You can toggle the isSecureTextEntry
property value to enable this functionality. So, let’s create a static computed property for UIView
, where we will extract this secure view from UITextField
and return its value.
extension UIView {
static var secureView: UIView {
let textField = UITextField()
textField.isSecureTextEntry = true
textField.isUserInteractionEnabled = false
guard let secureView = textField.layer.sublayers?.first?.delegate as? UIView else {
return .init()
}
secureView.subviews.forEach { subview in
subview.removeFromSuperview()
}
return secureView
}
}
Ok then, we can move to the SwiftUI solution.
SwiftUI
To use UIKit UIView
in the SwiftUI View
, we can create a UIViewRepresentable
instance. Here, we will provide a parent View
via initializer.
struct RestrictCaptureView<Content: View>: UIViewRepresentable {
private let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
}
In the makeUIView
method, we will create a UIHostingController
with our parent View
as its root view. Then, we will put this hosting controller’s view inside the secure view instance.
struct RestrictCaptureView<Content: View>: UIViewRepresentable {
private let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
func makeUIView(context: Context) -> UIView {
let secureView: UIView = .secureView
let hostingController = UIHostingController(rootView: content())
hostingController.view.backgroundColor = .clear
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
secureView.addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: secureView.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: secureView.bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: secureView.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: secureView.trailingAnchor)
])
return secureView
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
Now, we can create such an extension for View
.
extension View {
@ViewBuilder
func restrictCapture() -> some View {
RestrictCaptureView { self }
}
}
And use it.
struct ContentView: View {
var body: some View {
Text("Data to hide")
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.restrictCapture()
}
}
UIKit
We are finished with the SwiftUI solution. Now, let’s examine how we can do this with UIKit.
To secure the viewcontroller’s content, we can make its view secure. You can do this in the loadView
method or just use your secure view as viewcontroller’s view subview. Here, we will use the first option.
final class ViewController: UIViewController {
private let rootView: UIView = .init()
override func loadView() {
view = .secureView
}
override func viewDidLoad() {
super.viewDidLoad()
rootView.backgroundColor = .red
view.addSubview(rootView)
rootView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
rootView.topAnchor.constraint(equalTo: view.topAnchor),
rootView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
rootView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
rootView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
}
Conclusion
That’s it! We learned how to hide content from screen recording and prevent screenshots. Sure, the user can just take a photo or video via another smartphone. But there is no legal way to prevent such things.
If you enjoyed this article, please feel free to follow me on my social media: