-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathScreenshotPreventingView.swift
111 lines (83 loc) · 3.36 KB
/
ScreenshotPreventingView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//
// ScreenshotPreventingView.swift
//
//
// Created by David on 2022/8/17.
//
import UIKit
public final class ScreenshotPreventingView: UIView {
// MARK: - 📌 Constants
// MARK: - 🔶 Properties
public var preventScreenCapture = true {
didSet {
textField.isSecureTextEntry = preventScreenCapture
}
}
/// Changing isUserInteractionEnabled value will also affect
/// isUserInteractionEnabled value of hidden content container.
///
/// To sync isUserInteractionEnabled value is to prevent a freeze bug
/// that is going to happen if you add a scrollview inside `ScreenshotPreventingView`.
public override var isUserInteractionEnabled: Bool {
didSet {
hiddenContentContainer?.isUserInteractionEnabled = isUserInteractionEnabled
}
}
private var contentView: UIView?
private let textField = UITextField()
private let recognizer = HiddenContainerRecognizer()
private lazy var hiddenContentContainer: UIView? = try? recognizer.getHiddenContainer(from: textField)
// MARK: - 🎨 Style
// MARK: - 🧩 Subviews
// MARK: - 👆 Actions
// MARK: - 🔨 Initialization
public init(contentView: UIView? = nil) {
self.contentView = contentView
super.init(frame: .zero)
setupUI()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - 🖼 View Lifecycle
// MARK: - 🏗 UI
private func setupUI() {
textField.backgroundColor = .clear
textField.isUserInteractionEnabled = false
guard let container = hiddenContentContainer else { return }
addSubview(container)
container.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
container.leadingAnchor.constraint(equalTo: leadingAnchor),
container.trailingAnchor.constraint(equalTo: trailingAnchor),
container.topAnchor.constraint(equalTo: topAnchor),
container.bottomAnchor.constraint(equalTo: bottomAnchor)
])
DispatchQueue.main.async {
// setting secure text entry in init block will fail
// setting default value inside main thread
self.preventScreenCapture = true
}
guard let contentView = contentView else { return }
setup(contentView: contentView)
}
// MARK: - 🚌 Public Methods
public func setup(contentView: UIView) {
self.contentView?.removeFromSuperview()
self.contentView = contentView
guard let container = hiddenContentContainer else { return }
container.addSubview(contentView)
container.isUserInteractionEnabled = isUserInteractionEnabled
contentView.translatesAutoresizingMaskIntoConstraints = false
let bottomConstraint = contentView.bottomAnchor.constraint(equalTo: container.bottomAnchor)
bottomConstraint.priority = .required - 1
NSLayoutConstraint.activate([
contentView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: container.trailingAnchor),
contentView.topAnchor.constraint(equalTo: container.topAnchor),
bottomConstraint
])
}
// MARK: - 🔒 Private Methods
}
// MARK: - 🧶 Extensions