EditText实现undo/redo功能
一、设计思路
undo/redo有2种实现方式
- 数据——保存变化前的全部数据,undo时恢复之前的数据
- 变化——保存前后的数据变化,undo时执行相反的操作
实现方式 | 优点 | 缺点 |
---|---|---|
数据 | 实现简单 | 占用更多的空间 |
变化 | 节省空间 | 实现复杂 |
采用方式1(数据),在文章字数多的时候,将会占用非常大的储存空间。
比如《红楼梦》第一回《甄士隐梦幻识识通灵 贾雨村风尘怀闺秀》全文7911字,接近8000字。
即使增加一个换行符,也会保存8000个字符。
随着修改量增加,内存急剧地消耗。
没有特殊的理由,尽量不使用保存数据的方式来实现。
因此,我们主要考虑第2种方式——保存变化的方式。
二、已有的实现方案
1. AndroidEdit
GitHub开源项目——Android EditText的撤销和恢复(反撤销)
项目地址:https://github.com/qinci/AndroidEdit
2. MarkNote
之前推荐过的一款Markdown编辑器,支持undo/redo功能。
项目地址:https://github.com/Shouheng88/MarkNote
3. EditText
不用怀疑,就是Android开发经常使用到的EditText。
在Android 6.0(API 23)之前,EditText已经支持undo/redo,只是没有开放API,必须通过反射的方式才能调用。
在Android 6.0(API 23)及以后的版本,undo/redo功能进一步升级。
可以调用onTextContextMenuItem
接口,传入android.R.id.undo
或android.R.id.redo
实现undo/redo。
如果连接外部键盘,还可以使用快捷键Ctrl + Z/Ctrl + Shift + Z完成undo/redo。
比较3种已有的实现方案,自然是选择Android系统自带的实现方案。
虽然在Android 6.0之前没有开放API,系统本身也没有调用这些API。
但Android 6.0及之后,已经可以通过外接键盘实现undo/redo,说明API已经不仅仅是测试功能,而是可以在生产环境中使用的功能。
因此,果断选择使用系统自身API。
三、通过反射调用undo/redo功能
1. 需要实现的方法
方法 | 功能 | 调用方式 |
---|---|---|
undo() | 执行undo | 直接调用TextView#onTextContextMenuItem(android.R.id.undo) |
canUndo() | 判断能否undo,用于界面显示 | 反射调用TextView#canUndo() |
redo() | 执行redo | 直接调用TextView#onTextContextMenuItem(android.R.id.redo) |
canRedo() | 判断能否redo,用于界面显示 | 反射调用TextView#canRedo() |
forgetUndoRedo() | 清空undo/redo | 反射调用TextViw#mEditor,再次反射调用Editor#forgetUndoRedo() |
2. 最终代码
public class TextViewUtils {
public static final boolean canUndo(Tex