前言
對(duì)于富文本編輯器的實(shí)現(xiàn),首先我們肯定會(huì)想到實(shí)現(xiàn)的編輯器需要支持的幾個(gè)必要特性:
1.涉及大量文字,圖片,文字樣式的展示與編輯。
2.涉及極其復(fù)雜的用戶交互。
目前Github上我所了解的富文本編輯器基本上實(shí)現(xiàn)方式基于兩種:
- 1.基于WebView拓展的富文本編輯器。
- 2.基于EditText重寫的富文本編輯器。
對(duì)于這兩種方案,這里提出一些我個(gè)人的看法。
1.WebView實(shí)現(xiàn)
首先WebView的渲染性能一個(gè)弊端所在,其次當(dāng)涉及極其復(fù)雜的人機(jī)交互,WebView的實(shí)現(xiàn)起來就會(huì)比較困難。還有一點(diǎn)就是WebView的兼容性也是一個(gè)需要考慮的一點(diǎn)。
2.EditText重寫
對(duì)于重寫單個(gè)EditText,確實(shí)對(duì)于交互和文字渲染,樣式支持,都有很強(qiáng)的拓展性。但是考慮到會(huì)存在大量的圖片,這里就需要考慮到內(nèi)存的情況,對(duì)于EditText來說,肯定不存在View的復(fù)用,基本上有多少圖片,就要多少內(nèi)存。另一方面原生的TextView對(duì)于大量文字的渲染一直被人詬病,對(duì)此也有很多對(duì)于TextView的性能優(yōu)化的方案。
RecyclerView實(shí)現(xiàn)
所以我最終選擇使用RecyclerView作為實(shí)現(xiàn)富文本編輯器的實(shí)現(xiàn)方案。雖然有坑,但是也是一種可行性方案。(豆瓣的編輯器就是使用RecyclerView實(shí)現(xiàn))
優(yōu)點(diǎn):首先RecyclerVie作為一款原生組件,對(duì)于大量UI組件的展示有非常良好的性能,其次RecyclerView的復(fù)用機(jī)制對(duì)于內(nèi)存消耗的控制提供了的很好的支持。
缺點(diǎn)::當(dāng)然這里也不是說RecyclerView就絕對(duì)是實(shí)現(xiàn)富文本編輯器的首選方案,我在實(shí)現(xiàn)的過程中也遇到了很多大坑,這里就隨便列舉幾個(gè):
1.焦點(diǎn)的控制
2.數(shù)據(jù)的拼接
3.樣式的存儲(chǔ)
4.光標(biāo)的位置
and much more...
還好最后這些坑也找到了解決方案,所以這里分享一下這種實(shí)現(xiàn)方案,也為有需求的人提供一種可做參考的實(shí)現(xiàn)方案吧。
已實(shí)現(xiàn)功能
1.文本的粗體、斜體、下劃線、中劃線、刪除線、超鏈接、引用樣式、H1、H2、H3、H4。
2.圖片的插入和刪除
3.選中文本實(shí)時(shí)更改樣式
4.任意位置換行保持樣式。
5.兩行刪除為一行保持樣式。
6.隨光標(biāo)實(shí)時(shí)顯示文字樣式到控制面板。
7.任意位置插入樣式
8.最終編輯文本轉(zhuǎn)MarkDown(有Bug~。。。。)
等。。。
實(shí)現(xiàn)效果


對(duì)于RecyclerView實(shí)現(xiàn)而言,回車對(duì)應(yīng)的操作就是增加一個(gè)Model,所以回車換行和刪除就需要做非常多的邏輯情況處理,并且還涉及到樣式索引的拼接和分割,總之是一個(gè)大坑。

選中后,需要對(duì)光標(biāo),樣式的索引,樣式的清除和分割,還有樣式的重新創(chuàng)建和賦值,大坑啊大坑。

光標(biāo)對(duì)應(yīng)到對(duì)應(yīng)樣式的字符串時(shí),下面的面板對(duì)應(yīng)實(shí)時(shí)更改當(dāng)前樣式,需要利用區(qū)間的邏輯判斷,對(duì)光標(biāo)和樣式區(qū)間進(jìn)行邏輯判斷,坑越來越多。。。
還有許多復(fù)雜的交互處理,這里沒有展示,具體大家可以查看源碼。
項(xiàng)目地址
使用方式
這里并沒有將工程發(fā)布到JitPack,因?yàn)樽鳛橐豢罡晃谋揪庉嬈?,每人都有自己?dú)特的需求和交互方式,沒辦法做到一個(gè)富文本能夠應(yīng)付所有的需求。并且由于富文本編輯器的交互邏輯確實(shí)復(fù)雜,沒辦法保證兼容到所有到交互和情況,所以這里只是盡自己可能實(shí)現(xiàn)到交互情況。
1.引入editor的lib到工程
2.xml加入編輯器
<com.study.xuan.editor.widget.Editor
android:id="@+id/editor"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
就可以正常使用了。
進(jìn)階
簡(jiǎn)單到封裝了一下使用利用RichHelper
//綁定xml中的Editor
public void attach(Editor editor);
//new 一個(gè)Editor
public Editor buildEditor(Context context)
//部分事件回調(diào)
public void setCallBack(onEditorEventListener callBack)
//操作面板右側(cè)空白增加自定義布局
public void setMoreOperateLayout(View view)
//異步轉(zhuǎn)義MarkDown
public void toMarkDown()
public interface onEditorCallback {
//行數(shù)量變化時(shí)
void onLineNumChange(List<RichModel> data);
//點(diǎn)擊操作面板的圖片添加圖片,可以使用自己項(xiàng)目中的圖片框架,選中后對(duì)應(yīng)調(diào)用editor.addPhoto(List<String> data);方法即可
void onPhotoEvent();
//轉(zhuǎn)義MarkDown的進(jìn)度回調(diào)
void onMarkDownTaskDoing(int progress, int max);
//轉(zhuǎn)義MarkDown成功
void onMarkDownTaskFinished(String markdown);
}
架構(gòu)圖

1.RichBuilder
全局單例,底層架構(gòu),幫助RichEditor整體的功能實(shí)現(xiàn)。
1.1 IPanel
實(shí)現(xiàn)類PanelBuilder包含兩個(gè)實(shí)現(xiàn)類,F(xiàn)ontParamBuilder表示字符類型的樣式,ParagraphBuilder表示段落類型的樣式。Panle和Editor的通信方式是通過底層的RichBuilder單例中的IPanel。
1.2 IAbstractFactory
抽象工程類,用于外層對(duì)span類型的創(chuàng)建。其中抽象工廠又分為ICharacterStyleFactory,IParagraphFactory,IUpdateAppearanceFactory三種span工廠,分別對(duì)應(yīng)CharacterFactory(字符樣式span工廠),ParagraphFactory(段落樣式工廠),(自定義工廠未實(shí)現(xiàn))。
1.3 ISearchStrategy
搜索策略,用于對(duì)于某一段落中的span樣式的遍歷和處理,其中NormalSearch實(shí)現(xiàn)ISearchStrategy,利用常規(guī)遍歷處理(可以自定義實(shí)現(xiàn)快排或其他效率高的排序方式進(jìn)行處理)
1.4 IParamManager
參數(shù)管理接口,實(shí)現(xiàn)類對(duì)應(yīng)ParamManager,用于對(duì)當(dāng)前樣式和預(yù)輸入樣式的對(duì)比和處理。
2.Editor
編輯器實(shí)現(xiàn)類,繼承于RecyclerView,Adapter對(duì)應(yīng)RichAdapter,Model對(duì)應(yīng)RichModel。
2.1 ISpanFilter
輸入過濾器,用于對(duì)輸入和刪除時(shí)的樣式處理。
SpanStep1Filter
第一級(jí)過濾器,用于處理樣式的追加和混雜時(shí),對(duì)于SPAN_EXCLUSIVE_INCLUSIVE和SPAN_EXCLUSIVE_EXCLUSIVE的處理。
SpanStep2Filter
第二級(jí)過濾器,用于處理樣式的創(chuàng)建和保持,用于獲取當(dāng)前文本所有的樣式集,并記錄樣式對(duì)應(yīng)的index,保持到對(duì)應(yīng)的RichModel中。
2.2 ParseAsyncTask
異步處理,用于處理將數(shù)據(jù)轉(zhuǎn)換成對(duì)應(yīng)的轉(zhuǎn)換類型。
Parse
轉(zhuǎn)換接口
MarkDownParse
轉(zhuǎn)為MarkDown語法的邏輯處理,利用正則表達(dá)式。
2.3 RichModelHelper
數(shù)據(jù)處理類,用與合并樣式,處理樣式等相關(guān)的數(shù)據(jù)處理。
3.Panel
Panel表示操作面板,Panel默認(rèn)使用的是EditorPanelAlpha。Panel通過RichBuilder中的IPanel實(shí)現(xiàn)和編輯器Editor的聯(lián)動(dòng)。
總結(jié)
實(shí)現(xiàn)到過程中本來以為非常容易,結(jié)果實(shí)現(xiàn)到過程中發(fā)現(xiàn)坑越來越多,越來越大,但總算是將遇到的坑都找到了解決方案,從去年年底到上個(gè)月,前前后后大概開發(fā)了小半年,90多次commit也算是為大家踩踩坑,我認(rèn)為以RecyclerView作為基礎(chǔ)組件開發(fā)富文本編輯器,它在性能上到優(yōu)勢(shì),和原生到體驗(yàn),可以作為一種可行性方案作為參考依據(jù)。