富文本編輯器
考慮到富文本編輯需要支持長文本的類型,目前大部分富文本使用自定義單個的Edittext無法實現View的複用,於是利用RecycleView為基礎實現的富文本編輯器,目前處於開發過程中
對於富文本編輯器的實現,首先我們肯定會想到實現的編輯器需要支持的幾個必要特性:
1.涉及大量文字,圖片,文字樣式的展示與編輯。
2.涉及極其複雜的用戶交互。
目前Github上我所了解的富文本編輯器基本上實現方式基於兩種:
對於這兩種方案,這裡提出一些我個人的看法。
首先WebView的渲染性能一個弊端所在,其次當涉及極其複雜的人機交互,WebView的實現起來就會比較困難。還有一點就是WebView的兼容性也是一個需要考慮的一點。
對於重寫單個EditText,確實對於交互和文字渲染,樣式支持,都有很強的拓展性。但是考慮到會存在大量的圖片,這裡就需要考慮到內存的情況,對於EditText來說,肯定不存在View的複用,基本上有多少圖片,就要多少內存。另一方面原生的TextView對於大量文字的渲染一直被人詬病,對此也有很多對於TextView的性能優化的方案。
所以我最終選擇使用RecyclerView作為實現富文本編輯器的實現方案。雖然有坑,但是也是一種可行性方案。 (豆瓣的編輯器就是使用RecyclerView實現)
優點:首先RecyclerVie作為一款原生組件,對於大量UI組件的展示有非常良好的性能,其次RecyclerView的複用機制對於內存消耗的控制提供了的很好的支持。
缺點: :當然這裡也不是說RecyclerView就絕對是實現富文本編輯器的首選方案,我在實現的過程中也遇到了很多大坑,這裡就隨便列舉幾個:
1.焦點的控制
2.數據的拼接
3.樣式的存儲
4.光標的位置
and much more...
還好最後這些坑也找到了解決方案,所以這里分享一下這種實現方案,也為有需求的人提供一種可做參考的實現方案吧。
1.文本的粗體、斜體、下劃線、中劃線、刪除線、超鏈接、引用樣式、H1、H2、H3、H4。
2.圖片的插入和刪除
3.選中文本實時更改樣式
4.任意位置換行保持樣式。
5.兩行刪除為一行保持樣式。
6.隨光標實時顯示文字樣式到控制面板。
7.任意位置插入樣式
8.最終編輯文本轉MarkDown(有Bug~。。。。)
等。 。 。
對於RecyclerView實現而言,回車對應的操作就是增加一個Model,所以回車換行和刪除就需要做非常多的邏輯情況處理,並且還涉及到樣式索引的拼接和分割,總之是一個大坑。
選中後,需要對光標,樣式的索引,樣式的清除和分割,還有樣式的重新創建和賦值,大坑啊大坑。
光標對應到對應樣式的字符串時,下面的面闆對應實時更改當前樣式,需要利用區間的邏輯判斷,對光標和样式區間進行邏輯判斷,坑越來越多。 。 。
還有許多複雜的交互處理,這裡沒有展示,具體大家可以查看源碼。
RichEditor
這裡並沒有將工程發佈到JitPack,因為作為一款富文本編輯器,每人都有自己獨特的需求和交互方式,沒辦法做到一個富文本能夠應付所有的需求。並且由於富文本編輯器的交互邏輯確實複雜,沒辦法保證兼容到所有到交互和情況,所以這裡只是儘自己可能實現到交互情況。
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"/>
就可以正常使用了。
簡單到封裝了一下使用利用RichHelper
//绑定xml中的Editor
public void attach(Editor editor);
//new 一个Editor
public Editor buildEditor(Context context)
//部分事件回调
public void setCallBack(onEditorEventListener callBack)
//操作面板右侧空白增加自定义布局
public void setMoreOperateLayout(View view)
//异步转义MarkDown
public void toMarkDown()
public interface onEditorCallback {
//行数量变化时
void onLineNumChange(List<RichModel> data);
//点击操作面板的图片添加图片,可以使用自己项目中的图片框架,选中后对应调用editor.addPhoto(List<String> data);方法即可
void onPhotoEvent();
//转义MarkDown的进度回调
void onMarkDownTaskDoing(int progress, int max);
//转义MarkDown成功
void onMarkDownTaskFinished(String markdown);
}
全局單例,底層架構,幫助RichEditor整體的功能實現。
實現類PanelBuilder包含兩個實現類,FontParamBuilder表示字符類型的樣式,ParagraphBuilder表示段落類型的樣式。 Panle和Editor的通信方式是通過底層的RichBuilder單例中的IPanel。
抽象工程類,用於外層對span類型的創建。其中抽象工廠又分為ICharacterStyleFactory,IParagraphFactory,IUpdateAppearanceFactory三種span工廠,分別對應CharacterFactory(字符樣式span工廠),ParagraphFactory(段落樣式工廠),(自定義工廠未實現)。
搜索策略,用於對於某一段落中的span樣式的遍歷和處理,其中NormalSearch實現ISearchStrategy,利用常規遍歷處理(可以自定義實現快排或其他效率高的排序方式進行處理)
參數管理接口,實現類對應ParamManager,用於對當前樣式和預輸入樣式的對比和處理。
編輯器實現類,繼承於RecyclerView,Adapter對應RichAdapter,Model對應RichModel。
輸入過濾器,用於對輸入和刪除時的樣式處理。
SpanStep1Filter
第一級過濾器,用於處理樣式的追加和混雜時,對於SPAN_EXCLUSIVE_INCLUSIVE和SPAN_EXCLUSIVE_EXCLUSIVE的處理。
SpanStep2Filter
第二級過濾器,用於處理樣式的創建和保持,用於獲取當前文本所有的樣式集,並記錄樣式對應的index,保持到對應的RichModel中。
異步處理,用於處理將數據轉換成對應的轉換類型。
Parse
轉換接口
MarkDownParse
轉為MarkDown語法的邏輯處理,利用正則表達式。
數據處理類,用與合併樣式,處理樣式等相關的數據處理。
Panel表示操作面板,Panel默認使用的是EditorPanelAlpha。 Panel通過RichBuilder中的IPanel實現和編輯器Editor的聯動。
【2018.3.17】:一行文本內的富文本編輯。
【2018.3.19】:完成多行文本的刪除,增加一行,下一行刪除到上一行。並且保持樣式。
【2018.3.20】:完成多行文本的刪除和增加,包括首行回刪,行內回車,保持富文本樣式隨段落移動。
【2018.3.24】:完成點擊後操作欄的同步,保持當前文本的樣式和操作欄樣式統一。
【2018.3.29】:完成插入新樣式的功能,初步完成編輯的基本功能。
【2018.4.09】:完成段落樣式功能。
【2018.4.11】:初步完成MarkDown語法轉義。
Copyright 2017 [DrownCoder]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.