Skip to content

RESEARCH: Can we use existing widgets?

Matt Carroll edited this page Feb 20, 2021 · 1 revision

Can we use existing widgets?

We're building a rich text editor in Flutter. The most economical approach is to use existing widgets, wherever possible. However, we must take care when embracing existing widgets. A given widget might work for immediate needs, but be fundamentally unacceptable for known, future needs.

This document describes the analysis of various, existing Flutter widgets with regard to their suitability for use within this rich text editor implementation.

Text Editing and Display

TextField

In theory, a TextField widget could represent a single editable paragraph or list item within a rich text editor. Would that make sense?

https://api.flutter.dev/flutter/material/TextField-class.html

A TextField is described as an implementation of a "Material text field". In other words, the appearance and interactions implemented within a TextField adhere to the requirements of a standalone Material component for text entry. This use-case is so narrow that the documentation suggests a different widget should be used to achieve a "Cupertino" style. Given the specificity of the TextFields visual design and user interactions, it does not make sense to utilize TextField widgets within the rich text editor's implementation. Invariably, a lot of work would go into undoing behavior within TextField. Furthermore, TextField may implement undesired behaviors that can't be turned off or avoided.

TextField does not appear to be a legitimate option for implementing a rich text editor.

EditableText

In theory, a EditableText widget could represent a single editable paragraph or list item within a rich text editor. Would that make sense?

https://api.flutter.dev/flutter/widgets/EditableText-class.html

The EditableText widget is the workhorse for all text entry in Flutter, including the implementation of a TextField. EditableText is definitely a more appropriate alternative to TextField because EditableText avoids the opinionated Material component behaviors of TextField.

The documentation for EditableText references capabilities including: text selection, text entry, copy/paste popups, Android and iOS input actions, cursor appearance, and more. Are these behaviors helpful, harmful, or irrelevant for the rich text editor?

  • Android and iOS input actions: irrelevant for the rich text editor. We'll want to disable these because a mobile input field action like "Done" or "Emergency Call" or "Search" would make no sense for a paragraph or a list item in a rich text editor.
  • Cursor control: EditableText offers control over the cursor when it enters the widget. But this control is not specific enough. We need to control the cursor based on its position over actual text. This is a possible failure point.
  • Copy/Paste controls: EditableText includes the concept of a "toolbar", which can be configured to support a combination of cut, copy, and paste. The rich text editor needs to allow for a completely custom toolbar UI, and any given selection of actions. Those actions, including cut, copy, and paste must also defer to custom implementations. There is some level of control over the toolbar implementation. This is a possible failure point.
  • Text selection: EditableText supports text selection within itself. A quick experiment indicates that selection can't happen across EditableTexts using the standard implementation. I don't see any obvious place to override selection behavior to the degree that one could implement cross-widget selection. It might be possible to extend the underlying RenderObject and override the selection behavior from there. This is a likely failure point.
  • Scrolling: EditableText has scrolling built in. This will never be a desired capability for individual paragraphs or list items. It's a waste of widget tree build cycles, and layout cycles.

EditableText, or its underlying RenderEditable, might be appropriate for early development. It is probably not desirable for the final product because we don't need some of the internal widgets. For example: we never want scrolling on an individual paragraph basis, but every EditableText includes a Scrollable widget. We need to implement our own cursor control based on exact text boxes, which will override the MouseRegion widget within every EditableText. We may also want to avoid inheriting a bunch of unnecessary behaviors because if those behaviors change in the future, it might break the rich text editor.

Text

A Text widget is reasonable for text display, including rich text display. A rich text editor spike demonstrates that custom selection can be implemented with Text widgets in a regular widget tree.

However, all text displayed in the rich text editor must editable. There are no read-only requirements at the time of writing this analysis.

Theoretically, a Text widget could be used inside of a custom RichTextEditable widget. The Text widget would handle display responsibilities and the rest of the RichTextEditable would handle all other responsibilities, e.g., selection, text input, commands, etc. This might be a legitimate approach to early parts of the project. The final implementation might be better served with a custom RenderObject that extends or re-implements RenderParagraph.