androidhtml富文本
① 如何实现一个 Android 端的富文本编辑器
在 Android 上实现富文本编辑器的思路大致分为三种:
使用多种 Layout 布局,每一种布局对应一种 HTML 格式,比如图片,比如顺序列表等。具体的实现例子可以参考这个链接。 Medium 和
Evernote 的富文本编辑就是采用这种方式实现的。总体来说比较复杂。
WebView + JavaScript 实现。现在 Web 端有很多成熟的 JavaScript 富文本编辑库,比如 Squire ,你只需要做好
WebView 和 JavaScript 的交互就可以了(多写回调函数)。理论上虽然是这么说,但是在实现过程你需要解决 WebView 的兼容性问题(
Android 4.4 及其以上版本和 4.4 以下版本的 WebView 内核不一样),以及其他一些不可预见的问题(比如就遇到无法粘贴文字的问题)。
EditText + Span 。 Android 的 TextView 原生支持诸如粗体、删除线、引用等 Span
,要实现简单的富文本编辑需求,可操作性还是比较大的。综合再三,选择了这种方式来实现自己的需求。
既然决定使用 EditText + Span 的方式来实现,必然要对相关的 API 有所了解。
首先来了解一下 Span 。Span 是一个强大的概念,有兴趣深入的同学推荐直接阅读这篇译文。
在这里主要使用两种类型的 Span :
继承自 CharacterStyle 的 Span ,比如 StyleSpan ,可以在字符级别上添加粗体,下划线等。
继承自 ParagraphStyle 的 Span ,比如 QuoteSpan ,可以为段落级别的文本添加引用。
接着需要一个可以将 Span 的效果设置进去的文本结构(即实现了 Spannable 接口), SpannableStringBuilder
是个不错的选择,同时 EditText 提供的 getEditableText() 方法也可以获得。通常只需要 getEditableText()
就可以了,但是在面对一些细节部分,可以使用 SpannableStringBuilder 预先设置相应的 Span ,再替换到原来的文本中。
设置 Span 的方式也很简单,需要调用 Spannable.setSpan(Object what, int start, int end, int
flags) 这个方法即可,方法中 4 个参数的解释如下:
Object what ,传入你使用的 Span 对象。
int start ,设置 Span 的开始位置。
int end ,设置 Span 的结束位置。
int flags ,代表设置 Span 的作用域。
在这里重点介绍一下 int flags 这个参数,它接受 4 种类型的参数,分别是:
Spanned.SPAN_INCLUSIVE_EXCLUSIVE ,表示你在设置 Span 的区域之前输入文字,输入的文字也会受到 Span
的影响。
Spanned.SPAN_INCLUSIVE_INCLUSIVE ,表示你在设置 Span 的区域前后输入文字,输入的文字都后受到 Span
的影响。
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE ,表示你在设置 Span 的区域中出输入文字,输入的文字才会受到 Span
的影响。
Spanned.SPAN_EXCLUSIVE_INCLUSIVE ,表示你在设置 Span 的区域之后输入文字,输入的文字也会受到 Span
的影响。
“受到影响”的意思就是,仍然会保持你设置的 Span 的样式,比如选择Spanned.SPAN_EXCLUSIVE_INCLUSIVE
设置了一段文字的粗体,那么在这段文字后新输入的文字,也会是粗体。在这里推荐使用Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
参数,毕竟其他几种参数相对不是很好控制,而且会给使用的人带来的疑惑。认为一个操作代表的行为应当是准确没有歧义的。
好,到这里已经知道大致怎么作出一个富文本编辑器组件的样子了,无非是指定开始位置和结束位置,再设置相应的 Span
即可。至于设置的时候采取什么样的规则,你可以自己定制。但仅仅解决了编辑的问题,仍然存在导入的问题和导出的问题。
导入的问题十分简单, Android SDK 中提供了 Html.fromHtml() 这个方法,可以很轻松地将 HTML 字符串转换为所需的
Spanned 对象。但是需要注意的是, Html.fromHtml() 并不支持所有的 HTML 标签,比如无序列表就不支持,因此你需要自己实现
Html.TagHandler 接口来处理自己所需的标签,可以参考这个链接,实现了删除线和简单无序列表的支持。
面对粗体、斜体这样字符级别的样式, Html.fromHtml()
会自然而然的解析,该添加换行的地方就添加换行,并没有什么问题;但是面对引用、无序列表这样段落级别的样式,该方法会追加一个换行,也就是两个换行操作,相当于多出一个空行。通常来说认为一个
对应两个
,但是如果你有特别需求的话,也可以通过前面说的那样,自己来解析,而不是用系统默认的方式。
之前介绍了如何导入,想必你也十分清楚,必然有一个对应的Html.toHtml() 方法!没错,但是遗憾的是,这个方法也不全支持所有 Span
,比如列表就不支持。不过没有关系, Html.toHtml() 这个方法本身的源码简洁易懂,可以参考着实现。
在这里重点说明 Spannanle 的一个接口方法 nextSpanTransition(int start, int limit, Class
type) ,这个方法会在你指定的文本范围内,返回下一个你指定的 Span 类型的开始位置,依照这个方法,就可以逐层扫描指定的 Span
,而不用同时考虑其他类型的 Span 的影响,十分有用。
最后尽管说了这么多,导入导出还是有一个比较关键的问题,即导入的内容和导出的内容要保持一致,在这点上目前我还比较难以实现,只能说尽量控制吧,必要的时候还需要使用一下正则来处理导入导出的文本。
② 有道云笔记跨平台富文本编辑器的技术演进
有道云笔记提供跨平台的富文本编辑能力,包括Windows、Mac OS、桌面浏览器(webkit内核)、iOS、Android等终端。实现这一功能的关键在于跨平台架构设计,核心是使用前端技术构建编辑器并在特定的宿主环境——Native App提供的浏览器环境——中运行。不同平台使用的浏览器环境如下:
在Windows平台,客户端使用CEF(Chromium Embedded Framework)作为浏览器环境,它基于Chromium内核,支持跨Windows/Mac/Linux桌面平台,性能好,支持HTML5/CSS3等新特性。Android 4.0+ 中,有道云笔记使用了CrossWalk提供浏览器环境,旨在为Android 4.0+系统提供一个一致的性能强劲的WebView。然而,由于系统不断更新迭代,系统自带的WebView已使用Chromium内核,CrossWalk的优势在高版本Android中不明显。因此,在Android 7.0+中,使用了系统自带的WebView。
编辑器的迭代与设计选择主要围绕宿主环境的选择、内容编辑特性的实现和持久存储层的设计。早期版本的编辑器基于简单网页交互形式实现基本文本编辑,而随着技术发展,引入了浏览器的contenteditable特性,这使得编辑器能够实现更强大的富文本编辑功能。然而,contenteditable特性存在兼容性问题及浏览器间差异,因此在后续版本中,团队选择采用XML对数据及格式进行严格定义,分离数据层和视图层,实现更可控的编辑器功能。
第三代编辑器基于XML定义存储层,使用HTML内容与Range快照实现undo/redo功能,并对输入的HTML内容进行过滤处理,以确保数据的正确性和一致性。同时,编辑器与Native App的通信更加紧密,提供了一系列接口以访问设备功能,如持久存储、相册相机和震动器,从而实现更丰富和可靠的功能。
超越contenteditable的编辑器实现则涉及到XML定义数据层、分离数据层与视图层、实现细粒度的undo/redo机制、以及应对协同编辑需求。这一过程涉及从数据结构到命令执行、再到视图更新的全面设计,旨在提供更高效、更灵活的编辑体验。
总之,有道云笔记的富文本编辑器通过跨平台架构设计、迭代优化以及对内容处理机制的深入探索,实现了在不同终端上提供一致且强大的编辑能力,为用户提供了便捷和高效的笔记编辑体验。
③ html移动端(微信)开发input输入框兼容性问题
文本框是网页开发中常见的一种输入控件,用于用户输入文本信息。它的功能和特性多种多样,包括可增长或固定高度、垂直或水平溢出、支持单行或多行输入、表情符号支持、富文本编辑、所见即所得模式、指令允许等。
实现一个文本框涉及到渲染、光标位置计算、用户输入处理等多个方面。渲染方面,需要根据输入的字符集合,将其正确显示在界面上。光标位置计算涉及到字符间的间距和屏幕尺寸,以确定光标应位于哪个位置。用户输入时,光标位置会随之变化,实现这一功能需要精确计算。
文本框的复杂性主要体现在不同条件下的行为处理,如添加新字符、删除字符、鼠标操作等。例如,当达到光标位置的上限或下限时,光标位置不会改变,而是改变显示文本的窗口。鼠标操作如点击和拖动也需要精确计算,以适应不同场景。
引入可变宽度字体和富文本功能增加了实现的难度。可变宽度字体要求更复杂的光标位置计算和鼠标操作处理,以适应字体宽度的变化。而富文本功能要求对不同特性的文本部分进行精确处理和顺序渲染。
深入了解文本框的实现细节,能够帮助开发者更好地理解网页开发中输入控件的工作原理。这不仅有助于在实际项目中进行优化和创新,还能够激发开发者探索更多可能性,推动技术的发展和创新。在追求技术透明度的背景下,深入了解文本框的实现细节,能够帮助开发者跳出已有的框架,激发创造力,探索更高效、更符合用户需求的解决方案。
④ Android WebView 在开发过程中有哪些坑
多线程 如果在子线程中调用WebView的相关方法,而不在UI线程,则可能会出现无法预料的错误。 所以,当程序中需要用到多线程时候,也请使用 runOnUiThread()方法来保证关于WebView的操作是在UI线程中进行的: runOnUiThread(newRunnable(){ @Ov...
首先webview可以加载两种:1.带标签的富文本;2.网页地址。 1、加载富文本: webView.loadDataWithBaseURL(null, html, "text/html", "utf-8", null); 其中,加粗的地方是服务端返回的String类型的富文本,"text/html"是转换类型,utf-8是编码格...
下面说说我比较困惑的几个地方。 1.WebViewClient.onPageFinished()。你永远无法确定当WebView调用这个方法的时候,网页内容是否真的加载完毕了。当前正在加载的网页产生跳转的时候这个方法可能会被多次调用,StackOverflow上有比较具体的解释(...
注意4.4系统前后的区别,在这个版本里面谷歌把webview的内核换成谷歌浏览器的! 在webview中进行JavaScript交互时也要注意,出于对安全性的考虑,在设置与JavaScript有关的选项时,需要在所在方法的前面加上@SuppressLint({ "JavascriptInterfac...
自Android 4.4起,引入了webView,使用需要注意的事项: 1.多线程 如果你在子线程中调用WebView的相关方法,而不在UI线程,则可能会出现无法预料的错误。 所以,当你的程序中需要用到多线程时候,也请使用 runOnUiThread()方法来保证你关于WebVi...
Android开发需要注意的几项: 1、导入的类库需要和项目在同级目录下,谨防资源文件与类库中冲突。 2、textviewsetText为int时候,textview的color代码设置,set/getTextSize 单位问题。 3、json 属性节点不能有空格。 4、asset下使用第三方字体 ...
自Android 4.4起,引入了webView,使用需要注意的事项: 1.多线程 如果在子线程中调用WebView的相关方法,而不在UI线程,则可能会出现无法预料的错误。