Android:基于EditText实现撤销和重做机制
2016-12-02 23:22
375 查看
【转载请注明出处】
笔者:DrkCore (http://blog.csdn.net/DrkCore)
原文链接:(http://blog.csdn.net/drkcore/article/details/53440392)
一 场景描述和思路分析
二 代码实现
如果你稍微懂点数据结构并且有着基础的封装思想的话,大体都能想到一些思路:
涉及到撤销和重做的大部分都是需要用户编辑的功能,如果你想在Android上基于EditText开发出一个文本编辑器的话,那么按照这个思路一步步实现肯定是没有问题的。
我们发现文本的编辑操作其实可以简化为插入、删除。用户选中文本后粘贴的操作,也就是替换,可以分解为删除选中文本后插入粘贴板内容。
接下来只要记录下输入和删除的操作就可以保存用户的操作了,这里我们可以使用EditText提供了
接下来请看代码实现。
之后我们要在用户编辑文本的时候生成对应的
之后的撤销重做就很简单了:
最后实现效果如图:
![](http://img.blog.csdn.net/20161210110115326?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRHJrQ29yZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
源代码请移步我的GitHub
笔者:DrkCore (http://blog.csdn.net/DrkCore)
原文链接:(http://blog.csdn.net/drkcore/article/details/53440392)
一 场景描述和思路分析
二 代码实现
一、 场景描述和思路分析
说到撤销和重做想必大家脑海中浮现的一定是Ctrl+Z、Ctrl+Y这两个快捷键,平常生产开发的时候也少不了要和这两个按键打交道。作为一个开发者笔者自然对其中的实现方法感到好奇,想必阅读此文的你也是一样的。如果你稍微懂点数据结构并且有着基础的封装思想的话,大体都能想到一些思路:
将用户操作抽象成一个接口,接口包含undo()和redo()两个方法,并用栈来记录操作的顺序,通过出入栈和调用两个方法来处理撤销和重做的逻辑。
涉及到撤销和重做的大部分都是需要用户编辑的功能,如果你想在Android上基于EditText开发出一个文本编辑器的话,那么按照这个思路一步步实现肯定是没有问题的。
我们发现文本的编辑操作其实可以简化为插入、删除。用户选中文本后粘贴的操作,也就是替换,可以分解为删除选中文本后插入粘贴板内容。
接下来只要记录下输入和删除的操作就可以保存用户的操作了,这里我们可以使用EditText提供了
TextWatcher用于监听文本变化。
接下来请看代码实现。
二、 代码实现
首先我们需要实现编辑操作类,代码如下:class EditOperation implements Parcelable, Serializable { //原始内容,通常是被删除的部分 private String src; private int srcStart; private int srcEnd; //目标内容,通常是输入的部分 private String dst; private int dstStart; private int dstEnd; EditOperation setSrc(CharSequence src, int srcStart, int srcEnd) { this.src = src != null ? src.toString() : ""; this.srcStart = srcStart; this.srcEnd = srcEnd; return this; } EditOperation setDst(CharSequence dst, int dstStart, int dstEnd) { this.dst = dst != null ? dst.toString() : ""; this.dstStart = dstStart; this.dstEnd = dstEnd; return this; } void undo(EditText text) { Editable editable = text.getText(); int idx = -1; if (dstEnd > 0) {//删除目标内容 editable.delete(dstStart, dstEnd); if (src == null) { idx = dstStart; } } if (src != null) {//插入原始内容 editable.insert(srcStart, src); idx = srcStart + src.length(); } if (idx >= 0) {//恢复光标位置 text.setSelection(idx); } } void redo(EditText text) { Editable editable = text.getText(); int idx = -1; if (srcEnd > 0) {//删除原始内容 editable.delete(srcStart, srcEnd); if (dst == null) { idx = srcStart; } } if (dst != null) {//插入目标内容 editable.insert(dstStart, dst); idx = dstStart + dst.length(); } if (idx >= 0) {//恢复光标位置 text.setSelection(idx); } } }
之后我们要在用户编辑文本的时候生成对应的
EditOperation实例,也就是实现
TextWatcher:
public class OperationManager implements TextWatcher { private EditOperation opt; //启用开关,用于过滤撤销/重做时的编辑操作 private boolean enable = true; OperationManager disable() { enable = false; return this; } OperationManager enable() { enable = true; return this; } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (count > 0) { int end = start + count; if (enable) { if (opt == null) { opt = new EditOperation(); } //记录原始内容 opt.setSrc(s.subSequence(start, end), start, end); } } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (count > 0) { int end = start + count; if (enable) { if (opt == null) { opt = new EditOperation(); } //记录目标内容 opt.setDst(s.subSequence(start, end), start, end); } } } @Override public void afterTextChanged(Editable s) { if (enable && opt != null) { if (!redoOpts.isEmpty()) {//重做栈不空时用户又编辑了文本,视为抛弃重做栈 redoOpts.clear(); } //将操作入栈 undoOpts.push(opt); } opt = null; } //使用LinkedList代替栈 private final LinkedList<EditOperation> undoOpts = new LinkedList<>(); private final LinkedList<EditOperation> redoOpts = new LinkedList<>(); }
之后的撤销重做就很简单了:
public boolean undo() { if (canUndo()) { EditOperation undoOpt = undoOpts.pop(); //屏蔽撤销产生的事件 disable(); undoOpt.undo(editText); enable(); //填入重做栈 redoOpts.push(undoOpt); return true; } return false; } public boolean redo() { if (canRedo()) { EditOperation redoOpt = redoOpts.pop(); //屏蔽重做产生的事件 disable(); redoOpt.redo(editText); enable(); //填入撤销 undoOpts.push(redoOpt); return true; } return false; }
最后实现效果如图:
源代码请移步我的GitHub
相关文章推荐
- Android基于广播事件机制实现简单定时提醒功能代码
- 基于EditText实现一个可以对编辑文本进行撤销与返回的文本编辑器
- Android简单涂鸦以及撤销、重做的实现方法
- Android简单涂鸦以及撤销、重做的实现方法
- 基于 Immutable.js 实现撤销重做功能的实例代码
- 基于rtsp的手机视频点播实现和研究(扩展支持android, ios平台)
- 【转】在android平台上实现基于xmpp的摄像头截屏发送
- 基于.NET 2.0的GIS开源项目SharpMap分析手记(十四):ASP.NET2.0实现无刷新客户端回调的Callback机制及例子代码下载
- 基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现
- 采用双内核机制基于uClinux的实时操作系统分析与实现 form:http://www.eetchina.com
- Android HAL实现的三种方式(1) - 基于JNI的简单HAL设计 推荐
- 基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现
- C/S模式根据权限基于反射机制实现动态生成菜单
- Android HAL实现的三种方式(3) - 基于Manager的HAL设计
- 实现基于Android的英文电子词典
- 实现基于Android的英文电子词典
- .NET平台自带的AOP机制 转自《设计模式--基于c#的工程化实现及扩展》
- 图像的单步撤销和重做怎么实现,如何记录状态
- 使用Command模式实现撤销机制 (Code Project 精选翻译)
- Castle AOP 系列(四):实现一个简单的基于上下文调用的权限校验机制