这个随笔的内容以上一个随笔为基础,(在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(撤销/重做)操作的更多相关文章

  1. C#中泛型容器Stack<T>的用法,以及借此实现”撤销/重做”功能

    .Net为我们提供了众多的泛型集合.比如,Stack<T>先进后出,Queue<T>先进先出,List<T>集合元素可排序,支持索引,LinkedList<T ...

  2. 在iOS中实现一个简单的画板App

    在这个随笔中,我们要为iPhone实现一个简单的画板App. 首先需要指出的是,这个demo中使用QuarzCore进行绘画,而不是OpenGL.这两个都可以实现类似的功能,区别是OpenGL更快,但 ...

  3. 从Undo,Redo谈命令模式

    一般的应用软件中,通常会提供Redo和Undo的操作,比如Paint.NET中的动作面板,Word中的撤销重做,一般我们按Ctrl-Z即可回退到上次操作. 要实现上面的这一功能,最直观的想法就是,我们 ...

  4. Undo/Redo for Qt Tree Model

    Undo/Redo for Qt Tree Model eryar@163.com Abstract. Qt contains a set of item view classes that use ...

  5. IOS开始对App Store大扫除:你的APP更新了吗?

    成都亿合科技小编从北京商报了解到,对于开发APP应用的要注意啦,IOS要开始对App Store大扫除:你的APP更新了吗? 日前苹果App Store的开发者们发送邮件,表示将实施一个持续评估应用行 ...

  6. iOS UIKit:App

    1.App生命周期 IOS架构是由许多设计模式实现,如model-view-controller 和 delegation模式. 1.1 main函数 与其它框架类似,IOS框架的入口也是从main函 ...

  7. iOS 轻松使用 App 数据统计

    想获取用户各项行为数据吗? 想轻松查看用户行为图表吗? 想高效进行 App 运营管理吗? 想,来我带你玩转 App 数据统计.这里我使用专业.轻便的 JAnalytics. 本文内容分为两部分:代码示 ...

  8. ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开

    ASP.NET MVC Filters 4种默认过滤器的使用[附示例]   过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响 ...

  9. 使用 WijmoJS 轻松实现撤消重做(Undo /Redo)

    使用 WijmoJS 轻松实现撤消重做(Undo /Redo) 在V2019.0 Update2 的全新版本中,WijmoJS能够轻松实现撤消和重做操作,使Web应用程序的使用更加友好.更加高效. 不 ...

随机推荐

  1. TODO:Laravel 内置简单登录

    TODO:Laravel 内置简单登录 1. 激活Laravel的Auth系统Laravel 利用 PHP 的新特性 trait 内置了非常完善好用的简单用户登录注册功能,适合一些不需要复杂用户权限管 ...

  2. ExtJS 4.2 业务开发(一)主页搭建

    本篇开始搭建一个ExtJS 4.2单页面应用, 这里先介绍主页的搭建,内容包括:主页结构说明.扩展功能等方面. 目录 1. 主页结构说明 2. 扩展功能 3. 在线演示 1. 主页结构说明 1.1 主 ...

  3. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  4. 一道返回num值的小题目

    题目描述: 实现fizzBuzz函数,参数num与返回值的关系如下: .如果num能同时被3和5整除,返回字符串fizzbuzz .如果num能被3整除,返回字符串fizz .如果num能被5整除,返 ...

  5. javascript中的操作符详解1

    好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...

  6. JAVA程序员常用软件整理下载

    ********为了大家学习方便,特意整理软件下载如下:*************Java类软件:-------------------------------JDK7.0:http://pan.ba ...

  7. 浅谈java异常[Exception]

    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java! 一. 异常的定义 在<java编程思想 ...

  8. Android之ContentProvider数据存储

    一.ContentProvider保存数据介绍 一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProvider是以类似数据库中表的方式将数 ...

  9. git

    CMD命令:git initgit add . [添加文件至暂存区]git commit -m '描述性语句 随意写即可'git branch gh-pages [创建仓库分支]git checkou ...

  10. 在centos7(EL7.3 即 kernel-3.10.0-514.X )上安装BCM4312无线网卡驱动要注意的问题

    我新装的centos7主机无法使用里面自带的网卡,查询后发现网卡型号为BCM4312.我在看资料安装的过程中遇到了些问题,纠结了好久,现在分享下要注意的点,为后来的遇到同样问题的人提供点帮助.现在开始 ...