RichEditor

Rich text editor

Considering that rich text editing needs to support the type of long text, at present, most of the rich text using a single Edittext customized cannot achieve View reuse, so the rich text editor based on RecycleView is currently in the development process

preface

When implementing a rich text editor, we must first think of several essential features that the implemented editor needs to support:

1. Display and edit of a large number of texts, pictures and text styles. 2. Extremely complex user interactions are involved.

The rich text editor I know on Github is basically implemented in two ways:

  • 1. Rich text editor based on WebView expansion.
  • 2. Rich text editor rewrite based on EditText.

Here are some of my personal views on both options.

1. The WebView

First of all, WebView rendering performance is a disadvantage, and second, when it involves extremely complex human-computer interaction, WebView implementation will be more difficult. WebView compatibility is another consideration.

2. The EditText rewrite

For overriding a single EditText, it’s really extensible for interaction and text rendering, style support. But given that there’s a lot of images, there’s a lot of memory that needs to be taken into account, and for EditText, there’s definitely no View reuse, basically as much memory as there are images. On the other hand, native TextView rendering for a large number of text has been criticized, there are many performance optimization schemes for TextView.

RecyclerView implementation

So I finally choose to use RecyclerView as the realization of rich text editor. Although there are pits, but it is also a feasible scheme. (The editor of Douban is to use RecyclerView) Advantages: First, RecyclerVie, as a native component, has very good performance for the display of a large number of UI components, and then RecyclerView reuse mechanism provides good support for the control of memory consumption. Disadvantages: : Of course, it is not that RecyclerView is absolutely the first choice to achieve rich text editor, I also encountered a lot of pits in the process of implementation, here are just a few: 1. Focus control 2. Data splicing 3. Style storage 4. Fortunately, these pits also found a solution, so here is a share of this implementation, and also for those who need a reference implementation of the solution.

Realized function

1. Bold, italic, underline, underscore, strikeout, hyperlink, quote style, H1, H2, H3, H4. 2. Insert and delete pictures 3. Select text to change style in real time 4. 5. Delete two lines and keep the style as one line. 6. Display the text style to the control panel in real time with the cursor. 7. Insert styles anywhere 8. Turn final edited text to MarkDown , etc…

Implementation effect


For RecyclerView realization, the corresponding operation of carriage return is to add a Model, so carriage return newline and delete need to do a lot of logical processing, and also involves the style index splicing and segmentation, in short, is a big pit.

Select, need to cursor, style index, style clear and split, and style re – create and assign, pit pit.

Cursor to the corresponding style of the string, the following panel corresponding to the real-time change of the current style, need to use the interval of logical judgment, the cursor and the style of the interval of logical judgment, pit more and more…

There are many complex interactive processing, not shown here, you can view the source code.

The project address

RichEditor

use

The project is not published to the JitPack because, as a rich text editor, everyone has their own unique requirements and interactions, and there is no way that one rich text can handle all of them. And because the interaction logic of rich text editor is really complicated, there is no way to ensure compatibility with all the interactions and situations, so here we just try our best to achieve the interaction situation.

1. Add the editor’s lib to the project. 2

<com.study.xuan.editor.widget.Editor
        android:id="@+id/editor"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
Copy the code

It can be used normally.

The advanced

Simple to encapsulate the following uses using RichHelper

Public void attach(Editor Editor); // New an Editor public Editor buildEditor(Context Context) // Partial event callback public voidsetCallBack(onEditorEventListener CallBack) // Add custom layout public void on the right of operation panelsetMoreOperateLayout(View View) public void toMarkDown()Copy the code
Public interface onEditorCallback {// Void onLineNumChange(List<RichModel> data); AddPhoto (List<String> data); // Click the picture in the Actions panel to add an image. You can use the picture frame in your project. Void onPhotoEvent(); Void onMarkDownTaskDoing(int progress, int Max); // Escape MarkDown successfully void onMarkDownTaskFinished(String MarkDown); }Copy the code

Architecture diagram

1.RichBuilder

The global singleton, the underlying architecture, helps RichEditor implement its overall functionality.

1.1 IPanel

The implementation class PanelBuilder contains two implementation classes, FontParamBuilder for a style for a character type, and ParagraphBuilder for a style for a paragraph type. Panle communicates with the Editor through the IPanel in the underlying RichBuilder singleton.

1.2 IAbstractFactory

Abstract project class for outer creation of span type. The abstract factory is divided into ICharacterStyleFactory IParagraphFactory, IUpdateAppearanceFactory three span factory, corresponding CharacterFactory (character style span factory), ParagraphFactory(Paragraph style Factory), (a custom factory is not implemented).

1.3 ISearchStrategy

Search strategy for span-style traversal and processing of a paragraph, where NormalSearch implements ISearchStrategy and uses normal traversal processing (which can be customized to implement quick sorting or other efficient sorting methods for processing)

1.4 IParamManager

Parameter management interface, implementation class corresponding to ParamManager, used for the current style and pre-input style comparison and processing.

2.Editor

Editor implementation class, inherit in RecyclerView, Adapter corresponding RichAdapter, Model corresponding RichModel.

2.1 ISpanFilter

Input filters for styling input and delete. SpanStep1Filter Is the first level of filter for SPAN_EXCLUSIVE_INCLUSIVE and SPAN_EXCLUSIVE_EXCLUSIVE processing when dealing with style appends and confounding. SpanStep2Filter second level filter, used to handle the creation and retention of styles, used to get all the style sets of the current text, and record the corresponding index of the style, stored in the corresponding RichModel.

2.2 ParseAsyncTask

Asynchronous processing, used to process the conversion of data to the corresponding conversion type. Parse transforms the interface MarkDownParse into the logical processing of MarkDown syntax, using regular expressions.

2.3 RichModelHelper

Data processing classes that use data processing related to merge styles, processing styles, etc.

3.Panel

Panel represents the action Panel, and Panel defaults to EditorPanelAlpha. Panel realizes linkage with Editor through IPanel in RichBuilder.

conclusion

In the process of implementation, I thought it was very easy, but in the process of implementation, I found more and more pits, bigger and bigger, but I finally found a solution to all the pits I would encounter. From the end of last year to last month, I developed about half a year before and after, and I committed more than 90 times. I think RecyclerView as a basic component to develop rich text editor, its advantages in performance, and native to experience, can be used as a feasible scheme as a reference.