富文本编辑器 - RichEditor
基本功能
RichEditor
是一个继承自 WebView
的自己定义 view,枚举类型 Type
定了它所支持的排版格式:
public enum Type {
BOLD,
ITALIC,
SUBSCRIPT,
SUPERSCRIPT,
STRIKETHROUGH,
UNDERLINE,
H1,
H2,
H3,
H4,
H5,
H6
}
首先在构造函数中载入一个 html 文件。
private static final String SETUP_HTML = "file:///android_asset/editor.html"
public RichEditor(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setVerticalScrollBarEnabled(false);
setHorizontalScrollBarEnabled(false);
getSettings().setJavaScriptEnabled(true);
setWebChromeClient(new WebChromeClient());
setWebViewClient(createWebviewClient());
// 载入 html 文件
loadUrl(SETUP_HTML);
applyAttributes(context, attrs);
}
当中 html 文件 - editor.html
载入了两个 css 文件 - normalize.css
& style.css
。一个 js 文件 - rich_editor.js
。
body
中插入了一个 contentEditable="true"
的 div
。
<!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>
rich_editor.js
中定义了非常多排版功能的 API,RichEditor
相似 proxy。对外提供了 Java API。
public void setEditorFontColor(int color) {
String hex = convertHexColorString(color);
exec("javascript:RE.setBaseTextColor('" + hex + "');");
}
当中 exec
用于运行 js 代码。
protected void exec(final String trigger) {
if (isReady) {
load(trigger);
} else {
postDelayed(new Runnable() {
@Override public void run() {
exec(trigger);
}, 100);
}
}
}
仅仅有当 rich_editor.html
载入完毕后 isReady
才会被置为 true
。
protected class EditorWebViewClient extends WebViewClient {
@Override public void onPageFinished(WebView view, String url) {
isReady = url.equalsIgnoreCase(SETUP_HTML);
if (mLoadListener != null) {
mLoadListener.onAfterInitialLoad(isReady);
}
}
// other methods
}
构造函数在载入 editor.html
之前已经设置了一个 EditorWebViewClient
的实例。
public RichEditor(Context context, AttributeSet attrs, int defStyleAttr) {
// other statements
setWebViewClient(createWebviewClient());
loadUrl(SETUP_HTML)
// other statements
}
protected EditorWebViewClient createWebviewClient() {
return new EditorWebViewClient();
}
当 editor.html
载入完毕,isReady
被设为 true
之后,exec
方法就能够调用 load(trigger)
运行 js 了。
private void load(String trigger) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
evaluateJavascript(trigger, null);
} else {
loadUrl(trigger);
}
}
evaluateJavascript
以及 loadUrl
都是 Webview
提供的方法。
evaluateJavascript
是从 API 19 開始引入的。能够异步运行 js 代码。
Asynchronously evaluates JavaScript in the context of the currently displayed page.
SCHEME
RichEditor 提供了两个 Scheme 负责回调 java 代码。
private static final String CALLBACK_SCHEME = "re-callback://";
private static final String STATE_SCHEME = "re-state://";
然后在 EditorWebViewClient
中重写了 shouldOverrideUrlLoading
方法:
protected class EditorWebViewClient extends WebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
isReady = url.equalsIgnoreCase(SETUP_HTML);
if (mLoadListener != null) {
mLoadListener.onAfterInitialLoad(isReady);
}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
String decode;
try {
decode = URLDecoder.decode(url, "UTF-8");
} catch (UnsupportedEncodingException e) {
// No handling
return false;
}
if (TextUtils.indexOf(url, CALLBACK_SCHEME) == 0) {
callback(decode);
return true;
} else if (TextUtils.indexOf(url, STATE_SCHEME) == 0) {
stateCheck(decode);
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
}
假设 url 符合 CALLBACK 的 scheme,就会运行 callback
方法:
private void callback(String text) {
mContents = text.replaceFirst(CALLBACK_SCHEME, "");
if (mTextChangeListener != null) {
mTextChangeListener.onTextChange(mContents);
}
}
假设 url 符合 STATE 的 scheme。就会运行 stateCheck
方法:
private void stateCheck(String text) {
String state = text.replaceFirst(STATE_SCHEME, "").toUpperCase(Locale.ENGLISH);
List<Type> types = new ArrayList<>();
for (Type type : Type.values()) {
if (TextUtils.indexOf(state, type.name()) != -1) {
types.add(type);
}
}
if (mDecorationStateListener != null) {
mDecorationStateListener.onStateChangeListener(state, types);
}
}
通过下面两个 set 方法能够设置回调。
public void setOnDecorationChangeListener(OnDecorationStateListener listener) {
mDecorationStateListener = listener;
}
public void setOnInitialLoadListener(AfterInitialLoadListener listener) {
mLoadListener = listener;
}
总结
编辑器的核心功能由 js 实现,RichEditor 封装了 js 的功能。为上层提供了 java 接口。
參考
富文本编辑器 - RichEditor的更多相关文章
- Android 富文本编辑器实现方案
本人实现富文本编辑器的时候,总结了如下两种方案: 1. 纯 EditText 实现方案 2. 使用ScrollView作为最外层的父容器来控制展示效果 示例demo地址为:https://github ...
- 移动端强大的富文本编辑器richeditor-android
代码地址如下:http://www.demodashi.com/demo/14883.html 一.运行效果图 二.代码具体实现 1.引入richeditor-android richeditor-a ...
- 【JavaScript】富文本编辑器
这是js写的富文本编辑器,还存在一些bug,但基本功能已经实现,通过这个练习,巩固了js富文本编辑方面的知识,里面包含颜色选择器.全屏.表情.上传图片等功能,每个功能实际对应的就是一个小插件啦 部分程 ...
- Android 图片混排富文本编辑器控件
概述 一个Android 图片混排富文本编辑器控件(仿兴趣部落) 详细 代码下载:http://www.demodashi.com/demo/12032.html 一.一个Android 图片混排富文 ...
- vue中引入Tinymce富文本编辑器
最近想在项目上引入一个富文本编辑器,之前引入过summernote,感觉并不太适合vue使用, 然后在网上查了查,vue中使用Tinymce比较适合, 首先,我们在vue项目的components文件 ...
- 富文本编辑器Simditor的简易使用
最近打算自己做一个博客系统,并不打算使用帝国cms或者wordpress之类的做后台管理!自己处于学习阶段也就想把从前台到后台一起谢了.好了,废话不多说了,先来看看富文本编辑器SimDitor,这里是 ...
- 个人网站对xss跨站脚本攻击(重点是富文本编辑器情况)和sql注入攻击的防范
昨天本博客受到了xss跨站脚本注入攻击,3分钟攻陷--其实攻击者进攻的手法很简单,没啥技术含量.只能感叹自己之前竟然完全没防范. 这是数据库里留下的一些记录.最后那人弄了一个无限循环弹出框的脚本,估计 ...
- UEditor百度富文本编辑器--让编辑器自适应宽度的解决方案
UEditor百度富文本编辑器的initialFrameWidth属性,默认值是1000. 不能够自适应屏幕宽度.如图1: 刚开始的时候,我是直接设置initialFrameWidth=null的.效 ...
- PHP Ueditor 富文本编辑器
2016年12月11日 08:46:59 星期日 百度的简版富文本编辑器umeditor很久没更新了 全功能版本的配置项跟umeditor还是有区别的, 这里说下ueditor怎么对接到项目中去, 主 ...
随机推荐
- JavaScript基础深入之----参数传递的分析与总结
JS的数值类型是分为两类:基本数据类型和引用数据类型. 基本类型占据的内存栈空间,引用类型被保存在堆空间.引用类型赋值的变量也是被保存在栈空间的,它的作用类似于电视遥控器,负责操作堆空间内指向的对象. ...
- 学习javascript设计模式之中介者模式
1.中介者模式的作用就是解除对象与对象之间的紧耦合关系.增加一个中介者对象后,所有的相关对象都通过中介者来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介对象即可.中介者使各对象之间耦合 ...
- linux环境内存分配原理 mallocinfo【转】
转自:http://www.cnblogs.com/dongzhiquan/p/5621906.html Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和fr ...
- 算法 & 数据结构——任意多边形填充
需求 . 在计算机中,选区是一个很常见的功能,例如windows按住鼠标左键拖动划出矩形选区,Photshop通过钢笔工具任意形状选区.选区本身不过是通过线段闭合的一个几何形状,但是如何填充这个选区, ...
- 去掉 NavigationBar 底部的那条黑线
//加入下面两行代码即可[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UI ...
- js-斐波那切数列
f(1) = 1; f(2) = 1; f(3) = f(1) + f(2) = 2; f(4) = f(3) + f(2) = 3; f(5) = f(4) + f(3) = 5; f(6) = f ...
- 洛谷—— P2251 质量检测
https://www.luogu.org/problemnew/show/P2251 题目背景 无 题目描述 为了检测生产流水线上总共N件产品的质量,我们首先给每一件产品打一个分数A表示其品质,然后 ...
- CompletionService 与 ExecutorService 获取任务执行结果时的区别
CompletionService 与 ExecutorService 之间的区别 在讨论二者之间的区别之前,先交待一下背景. 看了ElasticSearch Transport模块的源码,里面充满了 ...
- gradle_____最后到齐的构建工具
从今年开始,开始换用gradle 了,个人感觉还好,配置不像maven,一堆xml 文件,一个jar 一行字符,内置的task 和很多.自定义task 也挺简单,比ant简单一些. 简单配置文件示例: ...
- 邁向IT專家成功之路的三十則鐵律 鐵律十:IT人思維之道-跳脫框架
莊子的哲學思想歸本於老子,他認為人要解脫束縛必須做到不從任何的角度與任何的時間來看待事物,而是必須與天地同體,然而也唯有如此才能看清宇宙間萬事萬理的真諦.無論是莊子還是老子,他們畢竟是中國古代的聖賢, ...