Blog Post

Adopting UITextInteraction

Illustration: Adopting UITextInteraction

In PSPDFKit 12.1 for iOS, we introduced Content Editor, which enabled users to edit text directly in PDF documents. To integrate text editing, it was important for us to have consistent rendering results, both while editing text and when viewing it. To accomplish this, we needed to be able to continue relying on our own rendering engine for creating visual representation of text in edit mode, instead of letting the system text input views handle this, all while still ensuring our users feel at home on iOS, iPadOS, and macOS. That said, we saw this as the perfect opportunity to try out UITextInteraction. This would allow us to make use of user interface (UI) components like text handles, as well as behavior and gestures, for text input fields users would expect on Apple platforms — all while handling rendering ourselves.

This post will cover what UITextInteraction enables and how to add it to your app if you have a custom text input field. What it won’t do is go into details on how to add underlying UITextInput support to your text components. Rather, it’ll look at the UI additions UITextInteraction enables once you add it on top of your existing text input view.

Introducing UITextInteraction

The UITextInteraction API was introduced at WWDC 2019 alongside iOS 13. It uses the UIInteraction system to add interactions to views that have adopted UITextInput. This enables you to add native text editing actions, a user interface, and gestures that you’d otherwise expect from a text input view on iOS. Previously, you would’ve needed to replicate the text interaction behavior yourself if you wanted it to match the system behavior. This meant that with each iOS update that changed text interaction behavior, you’d have to reverse engineer it and change your implementation if you wanted to match the system as closely as possible. With UITextInteraction, this is a thing of the past, and if any future iOS version updates the text interaction behavior, you’ll get it for free without doing anything. For example, the text loupe changes that were introduced in iOS 17 just work out of the box and behave the same as when you’re selecting text anywhere else on the system.

UITextInteraction handles all interactions related to text actions, selection, and input, including cursor rendering and manipulation, text selection, the edit menu, the magnifying glass, marked text support, keyboard shortcuts, the auto correction UI, Apple Pencil Scribble, and tap to start editing.

Since this is a system similar to what’s used by UITextField and UITextView, all your text interactions will look and behave the same as native text interaction.

It also adapts well to the platform it’s used on, like showing selection handles on iOS and iPadOS when not using a pointer, and omitting them on macOS and on iPadOS when a pointer input device is used.

You can choose whether you want UITextInteraction to be in editable or non-editable mode, depending on if the text in your field should be editable by the user. This changes which gestures and actions are added to the text input element.

Implementing UITextInteraction in Your App

To create and add the interaction to your text input field, you can use this code snippet:

let textInteraction = UITextInteraction(for: .editable)
textInteraction.textInput = textInput
textInput.addInteraction(textInteraction)

This assumes that textInput is a UIView subclass conforming to UITextInput. It’s important that your text field implements all the required UITextInput symbols correctly, as UITextInteraction heavily relies on this to provide the correct behavior.

Noteworthy Quirks

There are still a few shortcomings compared to using native UITextView or UITextField. For example, you can’t specify a given color as the text selection color; you’re always stuck with the default iOS blue for the text selection, the cursor, and the resize handles. Unless, of course, you make use of private APIs.

Additionally there’s a memory leak on versions prior to iOS 16 that you should be aware of: It keeps the text input around when spell checking is enabled. A workaround to this is to set autocorrectionType to .no on the affected versions.

Steve Shepard does a great job of listing internals, bugs, and tricks that are worth noting in Adventures with UITextInteraction. While some of the shortcomings were fixed in later iOS versions, the post still holds up in most points a few years later.

Conclusion

In this post, we covered how UITextInteraction can level up the look and feel of custom text input elements on iOS, iPadOS, and macOS to match system behavior. When releasing our Content Editor component — which allows users to edit text on document pages directly — using this interaction enabled us to rely on the system to provide us with default text editing support, while letting us remain in charge of rendering the text with our PDF renderer.

For a great open source text editor that implements UITextInteraction in a comprehensive way, have a look at Runestone by Simon Støvring.

Author
Stefan Kieleithner iOS Engineer

Stefan began his journey into iOS development in 2013 and has been passionate about it ever since. In his free time, he enjoys playing board and video games, spending time with his cats, and gardening on his balcony.

Related products
Share post
Free trial Ready to get started?
Free trial