#本文主要是講解部分原理,源碼及其使用請移步Github
https://github.com/RexSuper/RichEditor
APK:https://github.com/RexSuper/RichEditor/blob/master/RichHtmlEditorforAndroid/sample/release/sample-release.apk

Demo
https://github.com/RexSuper/RichEditor/tree/master/RichHtmlEditorforAndroid/sample
Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Step 2. Add the dependency
dependencies {
implementation 'com.github.RexSuper:RichEditor:1.0.5'
}
github上的示例代碼必須看,因為富文本有些功能後續不得不自己填充,比如使用者的資源檔案得先放到自己伺服器生成連結等等
2019-09-04 優化使用者體驗,在編輯時候所有資源改為本地,加載轉線上改為,最後統一釋出的時候
2019-08-20 增加音頻功能 增加連結下載下傳功能 和視訊下載下傳功能
2019-08-16 增加各種檔案功能
2019-08-15 增加添加視訊功能
2019-06-21 增加基本圖文混排等功能
目錄
源碼下載下傳
前言:
簡單版圖例
基本原理:最小模型示例
asset裡面放置一些靜态網頁和我們需要的初始化css
一個簡單的帶 contenteditable="true"的内容
安卓通過js和html互相調用 例如設定加粗
Webview中調用js中的加粗
1.網頁的contenteditable如何實作hint功能
2.如何擷取光标所在文字的所有style(需求場景 如選中了加粗 B變色,但你光标選中了)
4.如何自動換行
5.如何處理圖檔
6.自帶隻能實作固定幾種的font size (1-7自帶幾種)怎麼指定大小實作font-size
7.webview和js互動
8.如何在用戶端load自帶美化的css解決
9.事件監聽
源碼下載下傳
10.添加視訊
特别鳴謝
結尾:
前言:
富文本顯示還好,Android富文本編輯一直是一個大坑,還得考慮和其他端同步的問題,問題是你無論用什麼方式實作,EditText支援的标簽并不多,自定義span或者webview自定義标簽也較為繁瑣。
用html+webview+js肯定是最合适的可直接導出html相容性高,Android端用js調用本地靜态網頁中的contenteditable(此原理做IOS富文本編輯可以無縫照搬)
本文緻力于網絡常見能搜到的功能實作原理外,補全其他可能遇到的坑,網上能搜到的内容隻提關鍵字
本文也是基礎RichEditor for Android思路上一個優化和講解。它提供了如何和html edit之間交流。理論上來說html能實作的安卓就能實作了,我們隻是需要找到這些我們需要的方法
- 也可以用另一種了解方式,html本身就自帶這些所有功能,相容性又好,寫好html作為靜态放到用戶端本地。然後通過webview 用js去調這些功能。那為什麼不讓web前端做成線上的 再通過js調用呢?要讓安卓和ios來寫這些呢,我想一定是你的上司在 鼓勵你走向 真·全棧之路 的 第一步吧。既然要我們做,我們就得硬着頭皮做,還要做好~拿人錢财,替人浪費時間不是?
簡單版圖例
Video | Image | Audio | File And Download |
Italic | Subscript | Superscript | Strikethrough |
Underline | JustifyLeft | JustifyCenter | JustifyRight |
Blockquote | Heading | Undo | Redo |
Indent | Outdent | InsertLink | Checkbox |
TextColor | TextBackgroundColor | FontSize | UnorderedList |
OrderedList | Hint | NewLine | Blod |
android簡單富文本顯示基本原理:最小模型示例
- spannablestring和html.fromhtml +style 可以簡單使用為圖文混排,多種顔色但這種隻支援到h4部分标簽,很多内容如font-size都不支援,隻支援small big這樣的,此處順帶一提
-
android複雜富文本編輯和再現
如果你采用自定義原始view 1.編輯,2.整理成資料傳輸到背景再回來3.再現,三處都很複雜。如果使用html前端的自帶的edit,則可以不用考慮後面的問題,難點在于如果在安卓端去調用一個個功能,然後擷取其他狀态,光标等問題
- 編輯器的架構搭建(以加粗為例,其他居中 撤銷什麼的 均是一個邏輯 事件監聽 html自帶)最小實作模型
asset裡面放置一些靜态網頁和我們需要的初始化css
editor.html
一個簡單的帶 contenteditable="true"的内容
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="user-scalable=no">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="normalize.css" target="_blank" rel="external nofollow" >
<link rel="stylesheet" type="text/css" href="style.css" target="_blank" rel="external nofollow" >
</head>
<body>
<div id="editor" contenteditable="true"></div>
<script type="text/javascript" src="rich_editor.js"></script>
</body>
</html>
安卓通過js和html互相調用 例如設定加粗
rich_editor.js
RE.editor = document.getElementById('editor');
RE.setBold = function() {
document.execCommand('bold', false, null);
}
Webview中調用js中的加粗
//簡化最小模型代碼
public void setBold() {
exec("javascript:RE.setBold();");
}
public void exec(String trigger) {
load(trigger)
}
private void load(String trigger) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
evaluateJavascript(trigger, null);
} else {
loadUrl(trigger);
}
}
1.網頁的contenteditable如何實作hint功能
方法1:
editor.html
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.placeholder::after {
content: attr(placeholder);
position: absolute;
top: 10px;
color: #a9a9a9;
}
.placeholder-hide::after {
display:none;
}
</style>
</head>
<body>
<div class="editor placeholder" contenteditable="true" placeholder="你想說什麼"></div>
<script>
document.querySelector('.editor').addEventListener("input", function(event) {
var inputValue = event.target.innerHTML;
if (inputValue) {
document.querySelector('.editor').className = 'editor placeholder placeholder-hide'
} else {
document.querySelector('.editor').className = 'editor placeholder'
}
})
</script>
</body>
</html>
方法2
js
RE.setPlaceholder = function(placeholder) {
RE.editor.setAttribute("placeholder", placeholder);
}
css
#editor[placeholder]:empty:not(:focus):before {
content: attr(placeholder);
color: #9B9B9B;
font-size:15px;
}}
抽取成設定方法
<script>
function setPlaceholderColor (color) {
var placeHolderStyle = document.querySelector("#placeholder-style");
var styleContent = "#editor:empty:not(:focus):before {color:" + color +"}";
if (placeHolderStyle) {
placeHolderStyle.innerText = styleContent
} else {
placeHolderStyle = document.createElement('style')
placeHolderStyle.setAttribute('id', 'placeholder-style')
placeHolderStyle.innerText = styleContent
document.documentElement.appendChild(placeHolderStyle)
}
}
</script>
public void setPlaceholderColor(String color) {
exec("javascript:RE.setPlaceholderColor('" + color+ "');");
}
2.如何擷取光标所在文字的所有style(需求場景 如選中了加粗 B變色,但你光标選中了)
rich_editor.js
配合7:addEventListener
RE.getSelectedNode = function() {
var node,selection;
if (window.getSelection) {
selection = getSelection();
node = selection.anchorNode;
}
if (!node && document.selection) {
selection = document.selection
var range = selection.getRangeAt ? selection.getRangeAt(0) : selection.createRange();
node = range.commonAncestorContainer ? range.commonAncestorContainer :
range.parentElement ? range.parentElement() : range.item(0);
}
if (node) {
var item = (node.nodeName == "#text" ? node.parentNode : node);
console.log("innerHTML:"+item.innerHTML);
console.log("font-size:"+item.style["font-size"]);
console.log("color:"+item.getAttribute("color"));
console.log("queryCommandState1 bold:"+document.queryCommandState('bold'));
}
}
4.如何自動換行
public void setNewLine() {
exec("javascript:RE.prepareInsert();");
exec("javascript:RE.insertHTML('<br></br>');");
}
5.如何處理圖檔
5.1安卓實作webview圖檔點選放大方法回調
這種方式比網上搜出來PageFinish後要好
loadUrl("javascript:(function())有時候會因為加載問題,導緻代碼沒添加進去,那種有bug
現提供更好的方式,同時實作的
public final static String IMG_CLICK_JS = "<script type='text/javascript'>window.onload = function(){" +
"var $img = document.getElementsByTagName('img');" +
"for(var p in $img){" +
" if (typeof $img[p] === 'object') {" +
" $img[p].style.width = '100%';" +
" $img[p].style.height ='auto';" +
" $img[p].onclick = function(e){" +
" ImgClick(e.srcElement.src);" +
" };" +
" }" +
"}" +
"};" +
"function ImgClick(src) {" +
" var message = {" +
" 'imgUrl' : src," +
" };" +
" window.imageOnclick.openImage(src);" +
"};" +
"</script>";
*你也可以按照7.webview和js互動 console.log()傳值方式 替換window.imageOnclick.openImage(src);"
将上面代碼 直接加入到你的html中
實作對應回調
webview.getSettings().setJavaScriptEnabled(true);
webview.addJavascriptInterface(new JavascriptInterfaceImageOnclick(), "imageOnclick");
private class JavascriptInterfaceImageOnclick {
@android.webkit.JavascriptInterface
public void openImage(String imgUrl) {
if (mOnClickImageTagListener != null && !TextUtils.isEmpty(imgUrl)) {
mOnClickImageTagListener.onClick(imgUrl);
}
}
}
6.自帶隻能實作固定幾種的font size (1-7自帶幾種)怎麼指定大小實作font-size
//待更新
font size 類似于
- xx-small
- x-small
- small
- medium
- large
- x-large
-
xx-large
而我們需要 int px
7.webview和js互動
addJavascriptInterface
removeJavascriptInterface
evaluateJavascript
一般是addJavascriptInterface或者
shouldOverrideUrlLoading
接收資訊
其實最好用的是,也最安全
console.log() webview接收
editor(WebView)-->webChromeClient -->onConsoleMessage
8.如何在用戶端load自帶美化的css解決
1.不可二次編輯
loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding, String historyUrl)
2.可二次編輯
editor.loadCSS("file:///android_asset/article_night.css")
無法繼續編輯的問題
9.事件監聽
RE.editor.addEventListener("input", RE.callback);//其他html支援的 keyup ,selectionchange都支援 選中 文本變化 可以查下資料
源碼下載下傳
https://github.com/RexSuper/RichHtmlEditorForAndroid
一定要了解,不然産品随便有個新需求你将寸步難行
10.添加視訊
// 讓其可以繼續進去編輯模式
RE.insertVideo = function(url,custom) {
var html = ' <video src="' + url + '" ' + custom +'></video> ';
RE.insertHTML(html);
}
private void addVideo() {
//需要編輯框有光标才行
richEditor.focusEditor();
// pb.setVisibility(View.VISIBLE);
//将視訊上傳到自己伺服器得到連結
//============>
richEditor.setNeedSetNewLineAfter(true);
richEditor.insertVideo("https://www.w3school.com.cn/example/html5/mov_bbb.mp4",
//增加進度控制
"controls=\"controls\"" +
//視訊顯示第一幀
" initial-time=\"0.01\" " +
//寬高
"height=\"300\" " +
//樣式
" style=\"margin-top:10px;max-width:100%;\""
);
}
//臨時記錄
function insertHtml(html) {
var sel,range,div,node
sel = window.getSelection()//傳回一個Selection對象,用來表示使用者選擇的文本範圍或插入符目前位置。
range = sel.getRangeAt(0) //擷取Range,參數為0或其他能夠==0,如false,'',null
div=document.createElement('div')
div.innerHTML=html
node=div.firstChild
range.deleteContents()//删除目前range的内容
range.insertNode(node)//新增的節點内容
range.setStartAfter(node)//重新定位range(光标位置)
sel.removeAllRanges() //清除所有選中
sel.addRange(range) //将新定位的range加入
}
特别鳴謝
思路參考 RichEditor for Android
前端知識修正:@ZX
建立交流群
結尾:
這是一個不該由用戶端實作又可以實作的功能