Android富文本编辑器进阶版(干货,IOS可照搬逻辑)_android原生富文本编辑器-程序员宅基地

技术标签: 富文本编辑  iOS富文本编辑  android富文本编辑  

#本文主要是讲解部分原理,源码及其使用请移步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,则可以不用考虑后面的问题,难点在于如果在安卓端去调用一个个功能,然后获取其他状态,光标等问题
  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

新建交流群

 

结尾:

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

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_28844947/article/details/91870015

智能推荐

Sublime text 3搭建Python开发环境及常用插件安装_sublime python 环境搭建-程序员宅基地

文章浏览阅读4.9k次。Sublime text 3搭建Python开发环境及常用插件安装_sublime python 环境搭建

在CentOS 7上安装MySQL 8.0_centos7安装mysql8.0gpg密钥-程序员宅基地

文章浏览阅读643次。MySQL在首次安装后会执行一个安全脚本,用于设置root用户的密码以及其他安全选项。_centos7安装mysql8.0gpg密钥

echarts绘制圆角方形进度图_echarts symbolboundingdata-程序员宅基地

文章浏览阅读864次。这种场景下,可以使用两个系列,一个系列是完整的图形,当做『背景』来表达总数值,另一个系列是使用 `symbolClip` 进行剪裁过的图形,表达当前数值。_echarts symbolboundingdata

学python需要什么样的电脑,python需要什么样的电脑_python机器学习需要怎样配置的电脑-程序员宅基地

文章浏览阅读1k次,点赞18次,收藏16次。这篇文章主要介绍了学python对电脑配置要求高吗,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。_python机器学习需要怎样配置的电脑

最新OCR开源神器来了!-程序员宅基地

文章浏览阅读3.9k次。Datawhale开源开源方向:OCR开源项目01导读OCR方向的工程师,之前一定听说过PaddleOCR这个项目,其主要推荐的PP-OCR算法更是被国内外企业开发者广泛应用,短短半年..._github 2023年最新表格ocr

python 建筑建模_设计课开题 | Parameterized Complexities参数化建筑设计-程序员宅基地

文章浏览阅读317次。【竞赛+作品集,点燃你的设计理想】设计课开题啦!百川柯纳陆续推出以国际设计竞赛项目为参考的设计题目让大家参与,借此丰富履历,充实作品集。本期的设计题目为:Parameterized Complexities参数化建筑设计。喜欢参数化的小伙伴,你们兴奋吗?Parameterized Complexities 选题背景 近期不断有小伙伴在后台给我们留言,或者咨询百川柯纳顾问老师表达希望能够参加以“参数..._python 建筑平面图

随便推点

[ATF]-TEE/REE系统切换时ATF的寄存器的保存和恢复_atf-tee-程序员宅基地

文章浏览阅读1k次。ATF点滴1、设置运行时栈SP2、寄存器的保存和恢复的实现3、寄存器的保存和恢复的使用场景1、设置运行时栈SPbl31_entrypoint—>el3_entrypoint_common---->plat_set_my_stack—>platform_set_stack—>platform_get_stack动态找到该cpufunc platform_set_stackmov x9, x30 // lrbl platform_get_stackmov sp, x0r_atf-tee

PPT模板下载-程序员宅基地

文章浏览阅读134次。300多个各种类型的PPT模板下载,为您提供各种类型PPT模板、PPT图片、PPT素材、海报模板、新媒体配图等内容下载。

基于JAVA的智能小区物业管理系统【数据库设计、源码、开题报告】_智能化哪些系统需要数据库-程序员宅基地

文章浏览阅读546次。主要功能有:保安保洁管理、报修管理、房产信息管理、公告管理、管理员信息管理、业主信息管理、登录管理。_智能化哪些系统需要数据库

年度书单盘点 | 实用到爆炸,这份高性价比套系书单,越读越上头!-程序员宅基地

文章浏览阅读69次。本期年度书单,带大家盘点一下本年度图灵最受欢迎的套装图书,以前买套装书是为了凑单,如今套装书买回去不仅有一次性就能读完的酣畅感还极具收藏价值。一本好书往往要经过时间的验证,而阅读又是一种隐私,每个人的喜好大有不同,但能够集齐每个人的喜爱,这往往就是经典的诞生。今天这份书单里,有自成体系的套系书,还有一些因读者需求而产生的组成套系书。但不管哪种形式,它们都解决了读者在学习某些方面遇到的问题,也给大家...

thch30 steps/make_mfcc.sh详解-程序员宅基地

文章浏览阅读809次。这个脚本的输入参数有三个:1.data/mfcc/train 2.exp/make_mfcc/train 3.mfcc/train1.data/mfcc/train中有数据预处理后的一些文件:phone.txt spk2utt text utt2spk wav.scp word.txt2.exp/make_mfcc/train中应该是要保存程序运行的日志文件的3.mfcc/train中是提取出的特征文件1是输入目录,2,3是输出目录#!/bin/bash# Copyright 2012-2_thch30

smartclient listgrid style (加竖线、横线、背景色)_listgrid添加样式-程序员宅基地

文章浏览阅读2.5k次。如图所示:在jsp中引入: Style.css 代码:.myOtherGridCell { font-family:Verdana,Bitstream Vera Sans,sans-serif; font-size:11px; color:black; border-bottom:1px solid #a0a0a0;border-right:1px solid_listgrid添加样式