How Do I Customize the Appearance of PSPDFKit When Using React Native?

Q: How Do I Customize the Appearance of PSPDFKit When Using React Native?

A: To customize the appearance of user interface elements when using the PSPDFKit React Native wrapper for iOS, we recommend doing it directly in Objective-C, as this is simply a lot easier than exposing each and every single element to the javascript side.

As an example, consider we want to change the appearance of the navigation bar and the toolbars. We can add the following helper methods in the RCTPSPDFKitManager.m file:

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
- (void)customizeAppearanceOfNavigationBar {
  UIColor *backgroundColor = [UIColor colorWithRed:1.00 green:0.72 blue:0.30 alpha:1.0];
  UIColor *foregroundColor = [UIColor colorWithWhite:0.0 alpha:1];

  // Always use the new appearance customization API on iOS 13 or higher.
  // More info: https://developer.apple.com/documentation/uikit/uinavigationbar#1654334
  if (@available(iOS 13, *)) {
    UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
    appearance.titleTextAttributes = @{ NSForegroundColorAttributeName: foregroundColor };
    appearance.largeTitleTextAttributes = @{ NSForegroundColorAttributeName: foregroundColor };
    appearance.backgroundColor = backgroundColor;

    // Used when presenting PSPDFViewController directly inside a UINavigationController,
    // for example when using the `PSPDFKit.present` API in React Native.
    UINavigationBar *appearanceProxy = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[UINavigationController.class]];
    appearanceProxy.standardAppearance = appearance;
    appearanceProxy.compactAppearance = appearance;
    appearanceProxy.scrollEdgeAppearance = appearance;
    appearanceProxy.tintColor = foregroundColor;

    // Used when using the `PSPDFKitView` component in React Native.
    // The `PSPDFKitView` is embedded in its own `PSPDFNavigationController`.
    appearanceProxy = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[PSPDFNavigationController.class]];
    appearanceProxy.standardAppearance = appearance;
    appearanceProxy.compactAppearance = appearance;
    appearanceProxy.scrollEdgeAppearance = appearance;
    appearanceProxy.tintColor = foregroundColor;
  } else {
    // Used when presenting PSPDFViewController directly inside a UINavigationController,
    // for example when using the `PSPDFKit.present` API in React Native.
    UINavigationBar *appearanceProxy = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[UINavigationController.class]];
    appearanceProxy.titleTextAttributes = @{ NSForegroundColorAttributeName: foregroundColor };
    appearanceProxy.largeTitleTextAttributes = @{ NSForegroundColorAttributeName: foregroundColor };
    appearanceProxy.barTintColor = backgroundColor;
    appearanceProxy.tintColor = foregroundColor;

    // Used when using the `PSPDFKitView` component in React Native.
    // The `PSPDFKitView` is embedded in its own `PSPDFNavigationController`.
    appearanceProxy = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[PSPDFNavigationController.class]];
    appearanceProxy.titleTextAttributes = @{ NSForegroundColorAttributeName: foregroundColor };
    appearanceProxy.largeTitleTextAttributes = @{ NSForegroundColorAttributeName: foregroundColor };
    appearanceProxy.barTintColor = backgroundColor;
    appearanceProxy.tintColor = foregroundColor;
  }

  // Repeat the same customization steps for
  // [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[PSPDFNavigationController.class, UIPopoverPresentationController.class]];
  // if you want to customize the look of navigation bars in popovers on iPad as well.
}

- (void)customizeAppearanceOfToolbar {
  // Use dynamic colors for light mode and dark mode in iOS 13. Default to light mode on iOS 12 and lower.
  UIColor *backgroundColor = [UIColor colorWithRed:0.77 green:0.88 blue:0.65 alpha:1.0];
  UIColor *foregroundColor = [UIColor colorWithWhite:0.0 alpha:1];

  // Always use the new appearance customization API on iOS 13 or higher.
  // More info: https://developer.apple.com/documentation/uikit/uitoolbar#1652878
  if (@available(iOS 13, *)) {
    UIToolbarAppearance *appearance = [[UIToolbarAppearance alloc] init];
    appearance.backgroundColor = backgroundColor;

    PSPDFFlexibleToolbar *appearanceProxy = [PSPDFFlexibleToolbar appearance];
    appearanceProxy.standardAppearance = appearance;
    appearanceProxy.compactAppearance = appearance;
    appearanceProxy.tintColor = foregroundColor;
  } else {
    PSPDFFlexibleToolbar *appearanceProxy = [PSPDFFlexibleToolbar appearance];
    appearanceProxy.barTintColor = backgroundColor;
    appearanceProxy.tintColor = foregroundColor;
  }
}

Once we have these methods, we can directly call them at the relevant points in the app lifetime. For instance, one appropriate place to perform all the global theming would be to do it immediately after we set the license key in RCTPSPDFKitManager.m in the React Native wrapper like this:

Copy
1
2
3
4
5
6
7
8
9
10
RCT_REMAP_METHOD(setLicenseKey, setLicenseKey:(NSString *)licenseKey resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
  if (licenseKey.length > 0) {
    [PSPDFKitGlobal setLicenseKey:licenseKey];
    [self customizeAppearanceOfNavigationBar];
    [self customizeAppearanceOfToolbar];
    resolve(@(YES));
  } else {
    reject(@"error", @"Invalid License Key.", nil);
  }
}

For more information and examples about how to customize the UI by bridging Objective-C code to React Native, please take a look at the following blog posts: