Android实现undo/redo功能
一、目标
实现编辑器的undo/redo功能。
二、体验地址
神马笔记最新版本:【神马笔记 版本1.4.0.apk】
三、功能设计
功能设计要求:
- 实现undo/redo功能
- 显示undo/redo状态,操作无法执行时,必须显示为不可用状态
- 支持从外部键盘通过快捷键执行undo/redo
- 外部键盘与操作按钮的操作行为必须同步
四、准备工作
在上一篇文章中,已经介绍了Android的EditText
控件如何实现undo/redo功能。
具体内容详见《EditText实现undo/redo功能》。
需要注意的是,图文混排的实现方式采用的是RecyclerView
的方式,当插入图片时,其实是创建了多个EditText
控件,而不是单个EditText
控件。所以,无法通过undo功能撤销插入图片的操作。仅仅局限于EditText
的文本操作。
与此同时,正如Editor
中的一段注释所描述的,无法撤销Span
操作,目前只能处理文本内容的变化。
/**
* An InputFilter that monitors text input to maintain undo history. It does not modify the
* text being typed (and hence always returns null from the filter() method).
*
* TODO: Make this span aware.
*/
五、组合起来
1. UndoEditor
将TextViewUtils
的功能再次进行封装。
2. ParagraphEdit
对EditText
再次封装,使之直接支持undo/redo。
3. UndoHelper
功能设计2要求——显示undo/redo状态,操作无法执行时,必须显示为不可用状态。
同时一篇文章可能有1个或多个EditText
组成。
因此,在EditText
切换焦点时,必须更新undo/redo按钮状态,以指示操作是否可以执行。
OnGlobalFocusChangeListener
可以监听焦点控件的变化,从而实现这个功能。
另外,当EditText
文字内容发生变化时,同样需要更新按钮状态。
我们使用TextWatcher
来完成这个功能。
public class UndoHelper implements LifecycleObserver,
ViewTreeObserver.OnGlobalFocusChangeListener,
ViewTreeObserver.OnGlobalLayoutListener,
TextWatcher {
View decorView;
View undoBtn;
View redoBtn;
Fragment parent;
public UndoHelper(Fragment f, View undoBtn, View redoBtn) {
this.parent = f;
f.getLifecycle().addObserver(this);
this.undoBtn = undoBtn;
undoBtn.setEnabled(false);
undoBtn.setOnClickListener(this::onUndoClick);