Introducing Hakawai - a powerful, mentions-enabled text view for iOS

October 29, 2014

It's with great pleasure that I announce the first version of Hakawai, an open-source Objective-C library for iOS 7.1 (and newer) that exposes HKWTextView, a UITextView subclass with enhanced functionality.

Hakawai grew out of a project to extend the functionality of the basic iOS text view class. It features a number of additional APIs that simplify working with some of UITextView's advanced features. Its abstraction layer provides your application with clear, accurate notifications whenever the user changes its contents. And its plug-in architecture allows it to be extended in powerful ways while keeping the core code simple and clean.

Check it out at https://github.com/linkedin/Hakawai.

Text Transformers

Hakawai provides block-based APIs for working with the contents of a text view. Text transformers are methods which take in special blocks. These blocks always take as an argument an attributed string (representing the initial state of the text), and return another attributed string (representing the final state of the text). Hakawai also supports attribute transformers, which work similarly.

The example below implements a simple program to reverse the order of the selected characters whenever a button is tapped. For example, "Hello, world" would be reversed to form "dlrow ,olleH", and vice versa. The developer needs only worry about the actual transformation itself.

https://gist.github.com/austinzheng/d694393296a5c932f994.js

Hakawai's block-based APIs provide facilities for transforming, inserting, and deleting plain or attributed text, working either with the current selection or an arbitrary range of text, and for inserting text attachments.

Try out the block-based APIs by downloading the sample app and selecting the first tab.

Abstraction Layer

The experimental Abstraction Layer feature is a way to provide text view users with a higher-level change notification API than currently offered by the built-in UITextViewDelegate. There are five main types of notifications, each with associated data:

  • The user has inserted new text
  • The user has deleted text
  • The user has replaced text with other text
  • The user's text cursor was moved to a given location and is in text insertion mode
  • The user selected some text

Part of the goal of the Abstraction Layer is to properly handle a wide variety of edge cases. For example, the UITextViewDelegate method textView:shouldChangeTextInRange:replacementText:, usually used to indicate the user is attempting to change the contents of the text view, is not even called for some of the Chinese and Japanese two-stage IME keyboards. The textViewDidChangeSelection: delegate method is fired whether the selection change was due to the user moving the cursor or entering new text. The delegate methods are sometimes called when application code changes the text view's contents (by setting the text view's attributedText property), even when this is undesired.

The Abstraction Layer is designed to abstract away all sorts of implementation details, allowing the consumer to concentrate on the five main events described above. It handles Chinese and Japanese input, changes caused by autocorrection and iOS 8's predictive typing feature, as well as the built-in end-of-sentence space to period conversion triggered by tapping the space bar twice. The Abstraction Layer can be used to write a plug-in for Hakawai, or it can be cleanly removed and used with a vanilla UITextView. It does have a couple of current known limitations - for example, Korean language input is not yet properly handled.

See the Abstraction Layer in action by downloading the sample app and selecting the second tab.

Extras

Hakawai comes with a host of extras, including (but not limited to):

  • An API for easily adding and removing accessory views from the text view
  • An API for temporarily locking the focus of the text view to the top or bottom of the text view
  • An API for rejecting autocorrect suggestions, and for working with the text view's autocorrection, auto-capitalization, and spell checking state
  • A convenience API for working with characters and words at a given location
  • A custom text container and layout manager
  • Support for custom text formatting through custom attributes, including a pre-built attribute showcased in the mentions plug-in

API documentation can be found within the header files.

Plug-ins

Hakawai supports plug-ins, which are code modules that can be selectively activated and deactivated at run-time to provide the text view with additional functionality. An example of a plug-in is the mentions module which powers the optional mentions feature. It is intended that plug-ins can be written for Hawakai to fill many different purposes.

There are two basic types of plug-ins. Basic plug-ins do not receive notifications when events happen and are intended for simple text transformation operations (such as a plug-in that replaces text emoticons with their emoji equivalents). Control flow plug-ins are more sophisticated- they receive event notifications and are more deeply integrated with their host text views. There are two variants of control flow plug-ins: one which receives notifications via the UITextViewDelegate API, and one which receives notifications via the abstraction layer.

While multiple basic plug-ins may be registered at a time, only one control flow plug-in may be registered at a time.

Mentions

Mentions is a plug-in for creating 'mentions', annotations in a text view which might correspond to names of individuals or entities. Hakawai grew out of a desire to add mentions to the LinkedIn app, and many of the APIs provided by the text view were used to construct the plug-in. Check out the screenshot for an example of the plug-in in action.

The mentions plug-in is quite easy to use. The host app must provide a delegate with two main jobs:

  1. Given a search string, return an array of entities that corresponds to that string
  2. Given an entity, return a table view cell that corresponds to that entity (as well as its height)

Once that is finished, the mentions plug-in can be used by creating a new instance, configuring it properly, setting the delegate, and registering it to a Hakawai text view. The following code listing provides an example of how simple setup can be:

https://gist.github.com/austinzheng/45b7e28ee3614e7dd7a5.js

Check out the readme on Hakawai's GitHub repository for more details on the plug-in's features and operation. Try out the mentions plug-in by downloading the sample app and selecting the third tab.

Contributions

The hope is that Hakawai proves to be a useful tool. In order for this to happen, we welcome contributions, including feature requests, bug reports, pull requests, etc. If you think that the features Hakawai adds might be of interest to you, please do check out the repository on GitHub here.

Topics