最近看到了简书App中的编辑器可以实现字体的加粗,斜体,删除线等多种样式,而且可以插入图片,链接,分割线。支持字符串数据提交服务器,然后在TextView中直接展示。

如果我们没有了解其中原理之前,感觉还是挺高大上的。然后我就打算仿照他写一个类似的给大家分享。

开始我在网上找了一些类似的Demo,发现实现的关键原理是:通过WebView加载Html标签实现效果展示,然后最终获取全部的Html语句提交服务器,然后我们在请求服务器获取Html标签字符串,直接TextView展示。

不过在网上找了很多都最终达不到简书的那种效果,然后我就对部分进行了重写和添加,最终实现了和简书几乎一样的效果。

第一步:自定义WebView并初始Html化标签字符串

    private static final String SETUP_HTML = "file:///android_asset/editor.html";private static final String CALLBACK_SCHEME = "re-callback://";private static final String STATE_SCHEME = "re-state://";private boolean isReady = false;private String mContents;private OnTextChangeListener mTextChangeListener;private OnDecorationStateListener mDecorationStateListener;private AfterInitialLoadListener mLoadListener;private OnScrollChangedCallback mOnScrollChangedCallback;public RichEditor(Context context) {this(context, null);}public RichEditor(Context context, AttributeSet attrs) {this(context, attrs, android.R.attr.webViewStyle);}@SuppressLint("SetJavaScriptEnabled")public RichEditor(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);setVerticalScrollBarEnabled(false);setHorizontalScrollBarEnabled(false);getSettings().setJavaScriptEnabled(true);setWebChromeClient(new WebChromeClient());setWebViewClient(createWebviewClient());loadUrl(SETUP_HTML);applyAttributes(context, attrs);}
loadUrl(SETUP_HTML);
我们可以看到加载了一个本地的Html文件
<!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>
    <link rel="stylesheet" type="text/css" href="normalize.css"><link rel="stylesheet" type="text/css" href="style.css">
<pre name="code" class="html" style="font-size: 13.3333px;">    script type="text/javascript" src="rich_editor.js"></script>
在Html文件中连接了两个css文件和一个js文件
/*** Copyright (C) 2015 Wasabeef** 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.*/@charset "UTF-8";html {height: 100%;
}body {overflow: scroll;display: table;table-layout: fixed;width: 100%;min-height:100%;
}#editor {display: table-cell;-webkit-user-select: auto !important;-webkit-user-modify: read-write !important;outline: 0px solid transparent;background-repeat: no-repeat;background-position: center;background-size: cover;
}blockquote{
background-color: whitesmoke;
border-left: 4px solid #999999;
font-size: 15px;
font-weight: 100;
padding: 10px 15px;
margin-left: 0px;
margin-right : 0px;
}#editor[placeholder]:empty:not(:focus):before {content: attr(placeholder);opacity: .5;
}}

其余两个代码较多就不进行展示了,末尾有下载地址

开始编辑富文本

1,控件使用
 <span style="white-space:pre">    </span><com.niuduz.richeditor_ding.richeditor.RichEditorandroid:id="@+id/editor"android:layout_width="match_parent"android:layout_height="@dimen/dimen_300dip"android:layout_marginLeft="@dimen/dimen_5dip"android:layout_marginRight="@dimen/dimen_5dip"android:gravity="top|left"android:paddingTop="@dimen/dimen_10dip" />

2,添加按钮布局
 <RelativeLayoutandroid:id="@+id/rl_layout_editor"android:layout_width="match_parent"android:layout_height="wrap_content"android:visibility="invisible"><Viewandroid:layout_width="match_parent"android:layout_height="@dimen/dimen_1dip"android:layout_above="@+id/ll_layout_editor"android:background="@color/split_line_color" /><LinearLayoutandroid:id="@+id/ll_layout_editor"android:layout_width="match_parent"android:layout_height="@dimen/dimen_36dip"android:layout_alignParentBottom="true"android:background="@color/white"android:orientation="horizontal"><ImageButtonandroid:id="@+id/action_undo"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@null"android:contentDescription="@null"android:src="@mipmap/undo" /><ImageButtonandroid:id="@+id/action_redo"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@null"android:contentDescription="@null"android:src="@mipmap/redo" /><ImageButtonandroid:id="@+id/action_font"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@null"android:contentDescription="@null"android:src="@mipmap/font" /><ImageButtonandroid:id="@+id/action_add"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="@null"android:contentDescription="@null"android:src="@mipmap/add" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_layout_font"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_above="@+id/ll_layout_editor"android:layout_alignParentEnd="true"android:layout_marginBottom="-18dp"android:layout_marginRight="-5dp"android:background="@drawable/richfont_bg"android:gravity="center"android:orientation="horizontal"android:visibility="gone"><ImageButtonandroid:id="@+id/action_bold"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/bold_d" /><ImageButtonandroid:id="@+id/action_italic"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/italic_d" /><ImageButtonandroid:id="@+id/action_strikethrough"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/strikethrough_d" /><ImageButtonandroid:id="@+id/action_blockquote"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/blockquote_d" /><ImageButtonandroid:id="@+id/action_heading1"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/h1_d" /><ImageButtonandroid:id="@+id/action_heading2"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/h2_d" /><ImageButtonandroid:id="@+id/action_heading3"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/h3_d" /><ImageButtonandroid:id="@+id/action_heading4"android:layout_width="@dimen/dimen_36dip"android:layout_height="@dimen/dimen_36dip"android:background="@null"android:contentDescription="@null"android:src="@mipmap/h4_d" /></LinearLayout><LinearLayoutandroid:id="@+id/ll_layout_add"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_above="@+id/ll_layout_editor"android:layout_alignParentEnd="true"android:layout_marginBottom="-18dp"android:layout_marginRight="@dimen/dimen_12dip"android:background="@drawable/richadd_bg"android:gravity="center"android:orientation="horizontal"android:paddingLeft="@dimen/dimen_20dip"android:paddingRight="@dimen/dimen_20dip"android:visibility="gone"><ImageButtonandroid:id="@+id/action_image"android:layout_width="wrap_content"android:layout_height="match_parent"android:background="@null"android:contentDescription="@null"android:paddingRight="@dimen/dimen_10dip"android:src="@mipmap/insert_image" /><ImageButtonandroid:id="@+id/action_link"android:layout_width="wrap_content"android:layout_height="match_parent"android:background="@null"android:contentDescription="@null"android:paddingLeft="@dimen/dimen_10dip"android:paddingRight="@dimen/dimen_10dip"android:src="@mipmap/insert_link" /><ImageButtonandroid:id="@+id/action_split"android:layout_width="wrap_content"android:layout_height="match_parent"android:background="@null"android:contentDescription="@null"android:paddingLeft="@dimen/dimen_10dip"android:src="@mipmap/insert_split" /></LinearLayout></RelativeLayout>

· 3.注册RichEditor和各个按钮相关事件

 action_add.setOnClickListener(this);action_font.setOnClickListener(this);action_redo.setOnClickListener(this);action_undo.setOnClickListener(this);ib_Bold.setOnClickListener(this);ib_Italic.setOnClickListener(this);ib_StrikeThough.setOnClickListener(this);ib_BlockQuote.setOnClickListener(this);ib_H1.setOnClickListener(this);ib_H2.setOnClickListener(this);ib_H3.setOnClickListener(this);ib_H4.setOnClickListener(this);mEditor.setOnFocusChangeListener(new View.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {if (hasFocus) {imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED);rl_layout_editor.setVisibility(View.VISIBLE);
//                    clickableType = 1;} else {imm.hideSoftInputFromWindow(mEditor.getWindowToken(), 0); //强制隐藏键盘rl_layout_editor.setVisibility(View.INVISIBLE);}}});/***获取点击出文本的标签类型*/mEditor.setOnDecorationChangeListener(new RichEditor.OnDecorationStateListener() {@Overridepublic void onStateChangeListener(String text, List<RichEditor.Type> types) {if (types.contains(RichEditor.Type.BOLD)) {ib_Bold.setImageResource(R.mipmap.bold_l);flag1 = true;isBold = true;} else {ib_Bold.setImageResource(R.mipmap.bold_d);flag1 = false;isBold = false;}if (types.contains(RichEditor.Type.ITALIC)) {ib_Italic.setImageResource(R.mipmap.italic_l);flag2 = true;isItalic = true;} else {ib_Italic.setImageResource(R.mipmap.italic_d);flag2 = false;isItalic = false;}if (types.contains(RichEditor.Type.STRIKETHROUGH)) {ib_StrikeThough.setImageResource(R.mipmap.strikethrough_l);flag3 = true;isStrikeThrough = true;} else {ib_StrikeThough.setImageResource(R.mipmap.strikethrough_d);flag3 = false;isStrikeThrough = false;}//块引用if (types.contains(RichEditor.Type.BLOCKQUOTE)) {flag4 = true;flag5 = false;flag6 = false;flag7 = false;flag8 = false;isclick = true;ib_BlockQuote.setImageResource(R.mipmap.blockquote_l);ib_H1.setImageResource(R.mipmap.h1_d);ib_H2.setImageResource(R.mipmap.h2_d);ib_H3.setImageResource(R.mipmap.h3_d);ib_H4.setImageResource(R.mipmap.h4_d);} else {ib_BlockQuote.setImageResource(R.mipmap.blockquote_d);flag4 = false;isclick = false;}if (types.contains(RichEditor.Type.H1)) {flag4 = false;flag5 = true;flag6 = false;flag7 = false;flag8 = false;isclick = true;ib_BlockQuote.setImageResource(R.mipmap.blockquote_d);ib_H1.setImageResource(R.mipmap.h1_l);ib_H2.setImageResource(R.mipmap.h2_d);ib_H3.setImageResource(R.mipmap.h3_d);ib_H4.setImageResource(R.mipmap.h4_d);} else {ib_H1.setImageResource(R.mipmap.h1_d);flag5 = false;isclick = false;}if (types.contains(RichEditor.Type.H2)) {flag4 = false;flag5 = false;flag6 = true;flag7 = false;flag8 = false;isclick = true;ib_BlockQuote.setImageResource(R.mipmap.blockquote_d);ib_H1.setImageResource(R.mipmap.h1_d);ib_H2.setImageResource(R.mipmap.h2_l);ib_H3.setImageResource(R.mipmap.h3_d);ib_H4.setImageResource(R.mipmap.h4_d);} else {ib_H2.setImageResource(R.mipmap.h2_d);flag6 = false;isclick = false;}if (types.contains(RichEditor.Type.H3)) {flag4 = false;flag5 = false;flag6 = false;flag7 = true;flag8 = false;isclick = true;ib_BlockQuote.setImageResource(R.mipmap.blockquote_d);ib_H1.setImageResource(R.mipmap.h1_d);ib_H2.setImageResource(R.mipmap.h2_d);ib_H3.setImageResource(R.mipmap.h3_l);ib_H4.setImageResource(R.mipmap.h4_d);} else {ib_H4.setImageResource(R.mipmap.h3_d);flag7 = false;isclick = false;}if (types.contains(RichEditor.Type.H4)) {flag4 = false;flag5 = false;flag6 = false;flag7 = false;flag8 = true;isclick = true;ib_BlockQuote.setImageResource(R.mipmap.blockquote_d);ib_H1.setImageResource(R.mipmap.h1_d);ib_H2.setImageResource(R.mipmap.h2_d);ib_H3.setImageResource(R.mipmap.h3_d);ib_H4.setImageResource(R.mipmap.h4_l);} else {ib_H4.setImageResource(R.mipmap.h4_d);flag8 = false;isclick = false;}
然后在事件监听中,进行相关处理,这其中通常是对其他按钮作用的效果的添加和移除。这个是富文本中处理最麻烦的
因为WebView对标签的包裹并非统一实现了,基本原则:把出现标签的效果按钮就变亮;把没有出现标签效果的按钮变灰。
最后效果:

遗留问题

1,在模拟器上撤销和返回两个按钮好像有问题,在真机上完全没事!
2,在各个事件监听逻辑中,为了添加和消除其他按钮的影响时,产生了大量的重复代码,虽然大致相同,但还是存在区别,所以感觉抽取也不是,不抽取也不是。这方便有待优化,也请在有好的处理方法的话多多指出!
源码下载链接:http://download.csdn.net/detail/ding_gc/9656103

仿简书APP富文本编辑器实现相关推荐

  1. php+仿微信公众号样式,仿微信公众号富文本编辑器

    微信公众号富文本编辑器使用百度ueditor插件为基础加以封装 百度ueditor配置提供替换皮肤,只要添加相应的样式即可(码云代码链接) TIM截图20190404150153.png 以下处理富文 ...

  2. elementUI+froalaEditor实现仿微信公众号富文本编辑器

    首先上图 文章内容显示 编辑器安装:https://blog.csdn.net/weixin_39152200/article/details/106941233 下载地址:https://downl ...

  3. android简书app源码,仿简书APP源码(android)

    [实例简介] [实例截图] [核心代码] package com.yidou.wandou.example_33.ui; import android.content.Context; import ...

  4. vue项目:集成富文本编辑器 - 百度ueditor(vue-ueditor-wrap)

    一.背景 集成百度ueditor,实现图文编辑 二.项目介绍 vue---nuxt项目 vue项目:ueditor(vue-ueditor-wrap) 三.集成步骤 3.1.下载富文本编辑器 GitH ...

  5. 仿简书、淘宝等等App的View弹出效果

    昨天用简书App的时候觉得这个View的弹出效果特别好,而且非常平滑,所以我就尝试写了一个,和简书App上的效果基本一致了: 下面开始讲解: 1.首先我们要知道这个页面有几个View?这个页面其实有四 ...

  6. android仿简书编辑器,自己写一个类似知乎编辑器的编辑器(3)

    吃完饭回办公室,放一首歌<can't take my eyes off you>,戴上耳机,接着把昨天想写的富文本编辑器做完. 昨天已经搭好一个模型了.今天就是核心问题了:如何将div变成 ...

  7. Android仿简书、淘宝等APP View弹出效果

    在用简书App的时候觉得这个View的弹出效果特别好,而且非常平滑. 先看看效果: 主要是scale,alpha,translation几个普通动画组合,这里不再分析. 实现效果图: 代码:https ...

  8. 常用的六个富文本编辑器

    1::功能齐全 tinymce|TinyMCE | The Most Advanced WYSIWYG HTML Editor 官方网址:https://www.tinymce.com/ TinyMC ...

  9. flutter 富文本编辑器选择图片模糊_Flutter 到底香不香?看完这几个开源项目再做决定...

    Flutter 自 2015 年推出以来,凭借着其极高的开发交付效率,优秀的多平台能力,以及强大的 UI 表现力,受到了许多开发者们的推崇.虽然 Flutter 的确仍旧存在一些问题,但依然是不少开发 ...

最新文章

  1. library not found for -lAPOpenSdk解决方案
  2. flask之flask_socketio
  3. CUDA系列学习(四)Parallel Task类型 与 Memory Allocation
  4. webpack-dev-server 本地文件 发布 网站 域名 根目录
  5. c++计算园的面积与周长
  6. Java包范围可见性
  7. OpenCV-Python教程(10、直方图均衡化)
  8. proteus中ISIS软件的各种器件的添加
  9. Blender的一些使用小结,在辣椒酱基础上加了点,会持续更新
  10. centerX: 用中国特色社会主义的方式打开centernet
  11. 解决微信端苹果手机无法跳转页面的问题
  12. IE浏览器无法查看源文件的8大原因
  13. My console windows won't go away
  14. 收集了几个h5案例 与大家分享一下
  15. android 微信 耗电吗,微信太耗电了怎么办?微信耗电的两种解决方案
  16. 2022年10月 基于WPF的智能制造MES系统框架-菜单栏的设计
  17. Google 后 Hadoop 时代的新 “三驾马车” -- Caffeine(搜索)、Pregel(图计算)、Dremel(查询)
  18. 使用大神U盘工具安装原版系统的操作方法
  19. Sketch网页截屏插件设计开发
  20. uni-app封装自己常用的css样式-----自定义css的样式 (便于开发)-----原理简单

热门文章

  1. Andrew Ng 深度学习课程——序列模型
  2. 免费DSP开发板,你想要吗?
  3. 判断推理加强削弱强度关系
  4. 计算机原理存储器课件,计算机原理第五章存储器课件.ppt
  5. python编程midi键盘按键错乱_键盘按键错乱怎么办?
  6. 西门子plm_宇航联合西门子助力新能源汽车龙头企业比亚迪,打造PLM产品全生命周期的信息化管理...
  7. vscode跳转不到函数定义
  8. win7 计算机 开不了,win7系统开不了机怎么办?云骑士教你解决开不了机的问题...
  9. 如何重置ClearType设置?
  10. java 记牌_(笔记)JAVA--集合实现斗地主洗牌、发牌、看牌(利用TreeSet排序)