Blog Post

Customizable UI Components on iOS Using UIKit

Illustration: Customizable UI Components on iOS Using UIKit

As a framework vendor, we at PSPDFKit always have to keep in mind that we don’t have full control over the context of where the user interface (UI) of our SDK is used. We aren’t the ones making the decision on how an app should look — our customers are. Additionally, customers need to adapt the UI to the needs of their own apps to make them fit in.

In this post, we’ll go into details of how we make sure UI components are styled to have sensible defaults right out of the box, while also providing customization and styling options so that app developers can make the UI components we offer seamlessly blend into their apps’ styling. We’ll demonstrate this with our PSPDFKit for iOS framework, using an example of a UI component that we recently redesigned with UIKit.

Choosing Sensible Default Styling

A UI component can be any self-contained part of an interface that’s displayed onscreen — ranging from a simple button, to more complex parts like a toolbar or a list view. Usually on iOS, when using UIKit, such elements are descendants of UIView.

It’s often preferable for a framework to, for the most part, not make brave choices, and to stick to the behavior and design expected from the system. It’s also ideal to leverage as many of the system’s integrated options as possible — for example, Dynamic Type, Night mode, and the various accessibility options on iOS — to keep the UI adaptive to a user’s setting.

We try to find a good balance between keeping styling across our product palette on multiple platforms similar while still adopting platform features and aligning on the UI guidelines for any given platform as much as possible.

Making UI Components Customizable

Alongside making sure a UI component has a good default appearance, it might also be useful to add APIs that allow customizing the style of those components.

When using UIView subclasses for your customizable component, there are some built-in properties, like the tintColor or the backgroundColor. If you make use of those properties in your UI component, some parts of it might already be customizable out of the box, without the need to provide any additional APIs. PSPDFKit makes use of this approach in many UI components, including TextSelectionView and ToolbarButton. However in most cases, these customization options aren’t sufficient enough or might not be appropriate for the view you’re creating.

Using UIAppearance is another great approach for customization. For more information on this, refer to our Adopting UIAppearance in Custom Views post.

Usually, providing APIs to specify the style or the color directly on your UI component is the way to go. In cases where you want to offer deep customization, it’s also a good approach to directly expose a view property that customers can swap out — like a background view that, by default, has a certain styling — while also allowing customers to set their own background view for a component to handle all the styling themselves. There are also a quite a few UI components with these customization options in PSPDFKit, including Toolbar and NoteAnnotationViewController.

Redesigning the Tabbed Bar to Resemble the Navigation Bar

Recently, we redesigned the tabbed bar used to show multiple tabs of simultaneously open documents next to each other, along with the annotation toolbar, which shows tools available for annotating a document. When weighing how we could proceed, we decided to go in a direction that’s less opinionated on design language and that chooses a sensible default that blends in to the surrounding elements when integrated.

Providing a default option out of the box that fits within customers’ view hierarchies without explicit customization was an important goal. At the same time, we still wanted to allow certain customizations, so as to make the UI feel right at home on an app that uses a custom style.

After the Redesign Before the Redesign

In this particular case, we wanted to match the look of the tabbed bar to the UINavigationBar it’s attached to as closely as possible. To do this, we relied on UIToolbar and setting its appearance to the same values as the navigation bars. This included the UIBarAppearance properties on the navigation bar and adapting them so they work for the toolbar. Luckily, there’s a quick way to translate between them by using the init(barAppearance:) initializer:

func matchAppearance(from navigationBar: UINavigationBar) {
    self.backgroundToolbar.standardAppearance = UIToolbarAppearance(barAppearance: navigationBar.standardAppearance)
    if let compactAppearance = navigationBar.compactAppearance {
        self.backgroundToolbar.compactAppearance = UIToolbarAppearance(barAppearance: compactAppearance)
    }
}

This results in the tabbed bar background using the same styling as the navigation bar. So no matter what styling a customer’s app uses for the navigation bar — like being opaque, having a background color, etc. — it’ll all be matched in the toolbar we use for the tabbed bar.

Since we wanted to have different colors on tabs that are selected compared to tabs that aren’t, we needed to find a way that looks good no matter what the navigation bar styling looks like. Using a hardcoded color wasn’t an option, since that wouldn’t look great in conjunction with different styles of the navigation bar.

We worked closely with our Design team to come up with a solution that works for all common use cases. We use an overlaid visual effect view on the tabs that should look like they aren’t highlighted, which takes care of adapting to various navigation bar appearance configurations automatically without us needing to specify an actual color. Since we apply the navigation bar appearance to the tabbed bar, it automatically adjusts to the set background color, blur effect, and other styling-related properties.

Let’s consider an app that has the following navigation bar appearance configuration:

let appearance = UINavigationBarAppearance()
appearance.configureWithDefaultBackground()
appearance.backgroundColor = .systemGray2.withAlphaComponent(0.2)
navigationController.navigationBar.standardAppearance = appearance

The resulting UI would look like the following. Notice how the selected tab has the same background effect as the navigation bar.

Light Mode Dark Mode

Conclusion

In this post, we went over the importance of providing UI elements that fit in on iOS. We also discussed approaches on how to make these components customizable on iOS using UIKit, how to choose proper out-of-the-box styling defaults, and how to let customers of your SDK provide custom styling options for those components as well. Furthermore, we took a look at how we approached the redesign of a specific view in our SDK while keeping all of this in mind. We at PSPDFKit take this approach seriously, and we offer a wide range of customizable components. To learn more about customizing the UI in PSPDFKit for iOS, take a look at our UI customization guide.

Related Products
Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
PRODUCTS  |  iOS • Releases

PSPDFKit 13.4 for iOS Introduces Revamped API Documentation and Improves Multiple Annotation Selection

DEVELOPMENT  |  visionOS • iOS

Apple’s Vision of Our Digital Future

PRODUCTS  |  iOS • visionOS • Mac Catalyst • Releases

PSPDFKit 13.3 for iOS Adds Long-Term Validation for Digital Signatures