Android富文本编辑器进阶版(干货,IOS可照搬逻辑)

#本文主要是讲解部分原理,源码及其使用请移步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来写这些呢,我想一定是你的领导在 鼓励你走向 真·全栈之路 的 第一步吧。既然要我们做,我们就得硬着头皮做,还要做好~拿人钱财,替人浪费时间不是?

简单版图例

 

VideoImageAudioFile And Download
ItalicSubscriptSuperscriptStrikethrough
UnderlineJustifyLeftJustifyCenterJustifyRight
BlockquoteHeadingUndoRedo
IndentOutdentInsertLinkCheckbox
TextColorTextBackgroundColorFontSizeUnorderedList
OrderedListHint    NewLineBlod

 


 

android简单富文本显示基本原理:最小模型示例


  • spannablestring和html.fromhtml +style 可以简单使用为图文混排,多种颜色但这种只支持到h4部分标签,很多内容如font-size都不支持,只支持small big这样的,此处顺带一提
  • android复杂富文本编辑和再现
    如果你采用自定义原始view 1.编辑,2.整理成数据传输到后台再回来3.再现,三处都很复杂。如果使用html前端的自带的edit,则可以不用考虑后面的问题,难点在于如果在安卓端去调用一个个功能,然后获取其他状态,光标等问题
  1. 编辑器的框架搭建(以加粗为例,其他居中 撤销什么的 均是一个逻辑  事件监听 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">
    <link rel="stylesheet" type="text/css" href="style.css">
</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 lang="en">
<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.添加视频

//&nbsp; 让其可以继续进去编辑模式
RE.insertVideo = function(url,custom) {
    var html = '&nbsp;<video src="' + url + '" ' + custom +'></video>&nbsp;';
    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

新建交流群

 

结尾:

这是一个不该由客户端实现又可以实现的功能

 

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值