首页 > 代码库 > iOS: 为画板App增加 Undo/Redo(撤销/重做)操作

iOS: 为画板App增加 Undo/Redo(撤销/重做)操作

这个随笔的内容以上一个随笔为基础,(在iOS中实现一个简单的画板),上一个随笔实现了一个简单的画板:

 
今天我们要为这个画板增加Undo/Redo操作,当画错了一笔,可以撤销它,或者撤销之后后悔了,还可以还原。而且我们要通过晃动手机来触发Undo/Redo的选择。
 
这个demo使用NSUndoManager实现Undo/Redo操作,NSUndoManager 的实现原理是它作为一个记录器,每次数据变化,我们要用这个记录器记录一个相反的操作,当需要undo的时候,它通过执行这个相反的操作就可以实现了。对于这个画板demo,我们通过把array中的Line首尾连接起来实现的,所以要想还原到上次的状态,我们通过从array中remove最后添加的那条线就可以实现了。
 
NSUndoManager需要两个步骤:
第一步,注册NSUndoManger操作,既上边提到的注册一个相反的操作。(先只实现undo操作)
首先添加一个相反的操作,即一个从array中remove Line的方法,方法名就叫removeLine:
 
然后修改addLine方法,注册刚刚添加的removeLine方法:
 
但是这里有一个问题:因为当手指在屏幕移动的时候,touchMove方法会被持续多次触发,所以画一笔,是由多个Line组成的。所以addLine会调用多次,如果我们直接undo,只是remove掉了一条Line,但是画一笔是由多个Line组成,这样只能移掉一笔中的一部分,即结尾的那部分。
 
那要怎么办呢?如何一次移除多个Line,即画一笔所包含的一组Line。
NSUndoManager有一个分组的概念,就是为了解决这类问题的。
正常情况下,画一笔肯定会触发3个方法,依次是touchBegan, touchMove 和 touchEnd,所以我们可以通过touchBegan和touchEnd就能分辨出画一笔的开始和结束。既:
 
这样我们再执行撤销的时候就是一次remove一组的Line了。
 
第二步,执行Undo
在UI添加一个按钮,作为Undo按钮,按钮的点击事件中简单地调用undo方法就可以了。既:
 
Undo操作这样就算是完成了。
Redo操作和Undo操作道理一样,我们只需要修改下removeLine方法,当remove一条Line的时候,也注册一个相反的操作,即注册addLine方法,修改后的removeLine方法:
 
晃动触发Undo/Redo操作
其实我们根本不需要在UI添加Undo/Redo按钮,直接晃动手机就会自动弹出Undo/Redo选项,而且晃动的功能是自动打开的。
如果需要关闭它,需要设置:
在这个demo中,请不要将此属性设置为NO。
 
最后看下效果:(在模拟器中无法晃动,使用快捷键进行了模拟)
 

 

相关源代码:github 

iOS: 为画板App增加 Undo/Redo(撤销/重做)操作