State Customization


PSPDFViewController can be in 5 different states:

  • Default (Showing a PDF document)
  • Loading
  • Empty
  • Locked (Password protected PDF document)
  • Error

Take a look at PSPDFControllerState for more information.

You can change the state's strings and images or you can set -[PSPDFViewController overlayViewController] to take care of state handling yourself. To create an overlay view controller you have to implement the PSPDFControllerStateHandling protocol in an UIViewController subclass.

All states except locked are pretty forward to implement, because they don't feature any interaction.
To unlock documents you need to add a text field and handle the keyboard accordingly.
Use -PSPDFDocument unlockWithPassword: to unlock the document. After that you need to reload the PSPDFViewController with reloadData.

The following code snippets should help you create your own overlay view controller correctly:

Copy
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
class OverlayViewController: UIViewController, PSPDFControllerStateHandling {

    // MARK: Properties

    weak var pdfController: PSPDFViewController?

    private let label: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 0
        label.textColor = .gray
        label.textAlignment = .center
        return label
    }()

    private let textField: UITextField = {
        let textField = UITextField()
        textField.translatesAutoresizingMaskIntoConstraints = false
        textField.isSecureTextEntry = true
        textField.autocorrectionType = .no
        textField.autocapitalizationType = .none
        textField.borderStyle = .roundedRect
        return textField
    }()

    private let button: UIButton = {
        let button = UIButton(type: .system)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("Unlock", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.sizeToFit()
        return button
    }()

    // MARK: UIViewController

    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(unlock), for: .touchUpInside)

        let stackView = UIStackView(arrangedSubviews: [label, textField, button])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .fillEqually
        stackView.spacing = 20
        view.addSubview(stackView)

        NSLayoutConstraint.activate([
            stackView.widthAnchor.constraint(equalToConstant: 300),
            stackView.heightAnchor.constraint(equalToConstant: 150),
            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }

    // MARK: Button Actions

    @objc
    private func unlock(sender: UIButton) {
        guard let document = document, let password = textField.text else { return }
        document.unlock(withPassword: password)
        pdfController?.reloadData()
    }

    // MARK: PSPDFControllerStateHandling

    var document: PSPDFDocument?

    public func setControllerState(_ state: PSPDFControllerState, error: Error?, animated: Bool) {
        var text = ""
        var backgroundColor: UIColor? = .white

        switch state {
        case .default:
            backgroundColor = nil
        case .empty:
            text = "No document set"
        case .loading:
            text = "Loading..."
        case .locked:
            text = "Password:"
        case .error:
            text = "Unable to display document:\n\(error!.localizedDescription)"
        }

        label.text = text
        view.backgroundColor = backgroundColor
        view.isUserInteractionEnabled = state != .default

        if state == .locked {
            textField.isHidden = false
            button.isHidden = false
            textField.becomeFirstResponder()
        } else {
            textField.isHidden = true
            button.isHidden = true
            textField.resignFirstResponder()
        }
    }
}
Copy
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
112
113
@interface OverlayViewController : UIViewController <PSPDFControllerStateHandling>

@property (nonatomic, weak) PSPDFViewController *pdfController;

@end

@interface OverlayViewController ()

@property (nonatomic) UILabel *label;
@property (nonatomic) UITextField *textField;
@property (nonatomic) UIButton *button;

@end

@implementation OverlayViewController

#pragma mark - UIViewController

-(void)viewDidLoad {
    [super viewDidLoad];

    self.label = [UILabel new];
    self.label.translatesAutoresizingMaskIntoConstraints = NO;
    self.label.numberOfLines = 0;
    self.label.textColor = [UIColor grayColor];
    self.label.textAlignment = NSTextAlignmentCenter;

    self.textField = [UITextField new];
    self.textField.translatesAutoresizingMaskIntoConstraints = NO;
    self.textField.secureTextEntry = YES;
    self.textField.autocorrectionType = UITextAutocorrectionTypeNo;
    self.textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
    self.textField.borderStyle = UITextBorderStyleRoundedRect;

    self.button = [UIButton buttonWithType:UIButtonTypeSystem];
    self.button.translatesAutoresizingMaskIntoConstraints = NO;
    [self.button setTitle:@"Unlock" forState:UIControlStateNormal];
    [self.button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [self.button sizeToFit];
    [self.button addTarget:self action:@selector(unlock:) forControlEvents:UIControlEventTouchUpInside];

    UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:@[self.label, self.textField, self.button]];
    stackView.translatesAutoresizingMaskIntoConstraints = NO;
    stackView.axis = UILayoutConstraintAxisVertical;
    stackView.distribution = UIStackViewDistributionFillEqually;
    stackView.spacing = 20;
    [self.view addSubview:stackView];

    [NSLayoutConstraint activateConstraints:@[
        [stackView.widthAnchor constraintEqualToConstant:300],
        [stackView.heightAnchor constraintEqualToConstant:150],
        [stackView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [stackView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor]
    ]];
}

#pragma mark - Button Actions

- (void)unlock:(id)sender {
    NSString *password = self.textField.text;
    [self.document unlockWithPassword:password];
    [self.pdfController reloadData];
}

#pragma mark - PSPDFControllerStateHandling

@synthesize document;

-(void)setControllerState:(PSPDFControllerState)state error:(NSError *)error animated:(BOOL)animated {
    NSString *text = @"";
    UIColor *backgroundColor = [UIColor whiteColor];

    switch (state) {
        case PSPDFControllerStateDefault:
            backgroundColor = nil;
            break;

        case PSPDFControllerStateEmpty:
            text = @"No document set";
            break;

        case PSPDFControllerStateLoading:
            text = @"Loading...";
            break;

        case PSPDFControllerStateLocked:
            text = @"Password:";
            break;

        case PSPDFControllerStateError:
            text = [NSString stringWithFormat:@"Unable to display document:\n%@", error.localizedDescription];
            break;

        default:
            break;
    }

    self.label.text = text;
    self.view.backgroundColor = backgroundColor;
    self.view.userInteractionEnabled = state != PSPDFControllerStateDefault;

    if (state == PSPDFControllerStateLocked) {
        self.textField.hidden = NO;
        self.button.hidden = NO;
        [self.textField becomeFirstResponder];
    } else {
        self.textField.hidden = YES;
        self.button.hidden = YES;
        [self.textField resignFirstResponder];
    }
}

@end
Copy
1
2
3
4
let pdfController = PSPDFViewController(document: document)
let overlayViewController = OverlayViewController()
overlayViewController.pdfController = pdfController
pdfController.overlayViewController = overlayViewController
Copy
1
2
3
4
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:document];
OverlayViewController *overlayViewController = [OverlayViewController new];
overlayViewController.pdfController = pdfController;
pdfController.overlayViewController = overlayViewController;
Was this page helpful? We're happy to answer any questions.