這個隨筆的內容以上一個隨筆為基礎,(在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