当前位置: 首页 > news >正文

iOS绘图例2:增加Undo/Redo功能

为什么80%的码农都做不了架构师?>>>   hot3.png

  1. 在工程中添加Undo、Redo的按钮图片,每个按钮都有可用和不可用两种状态图片,共4个图片。

  2. 在StoryBoard中添加两个按钮,设置图片属性和自动布局约束。

  3. 按住 Ctrl 拖动按钮到 ViewController.mm 中,创建属性变量和动作方法。

     @interface ViewController ()
     @property (weak, nonatomic) IBOutlet UIButton *undoButton;
     @property (weak, nonatomic) IBOutlet UIButton *redoButton;
     @end
    
     @implementation ViewController
    
     - (void)viewDidLoad {
         [super viewDidLoad];
     }
    
     - (IBAction)undo:(id)sender {
     }
    
     - (IBAction)redo:(id)sender {
     }
    
     @end
    
  4. 在 ViewController.mm 中导入 GiViewHelper.h,在 viewDidLoad 中启用Undo功能,实现Undo/Redo按钮方法:

     - (void)viewDidLoad {
         [super viewDidLoad];
    
         NSString *path = [LIBRARY_FOLDER stringByAppendingString:@"undo"];
         [[GiViewHelper sharedInstance]startUndoRecord:path];
     }
    
     - (IBAction)undo:(id)sender {
         [[GiViewHelper sharedInstance]undo];
     }
    
     - (IBAction)redo:(id)sender {
         [[GiViewHelper sharedInstance]undo];
     }
    

    运行程序,画几个图,试试Undo/Redo按钮吧。虽然能工作了,但按钮可用状态未显示出来。

  5. 在 ViewController 中实现 GiPaintViewDelegate 观察者协议的 onContentChanged: 方法,注册此观察者。

     @interface ViewController ()<GiPaintViewDelegate>
     ...
     - (void)viewDidLoad {
         [super viewDidLoad];
         ...
         GiViewHelper *hlp = [GiViewHelper sharedInstance];
    
         [hlp startUndoRecord:[LIBRARY_FOLDER stringByAppendingString:@"undo"]];
         [hlp addDelegate:self];
         [self onContentChanged:hlp.view];
     }
    
     - (void)onContentChanged:(id)view {
         GiViewHelper *hlp = [GiViewHelper sharedInstance];
         self.undoButton.enabled = [hlp canUndo];
         self.redoButton.enabled = [hlp canRedo];
     }
    

样例代码见 GitHub 或 OSC,欢迎 Fork。

转载于:https://my.oschina.net/rhcad/blog/318775

相关文章:

  • grep简单用法及脚本基础篇
  • SysUtils.UpperCase、SysUtils.LowerCase - 大小写转换
  • 使用X-UA-Compatible来设置IE浏览器兼容模式
  • 区块链技术对未来的影响
  • Delphi 2009 新增的 Class Explorer
  • jar包和war包的区别:
  • 新手须知 C、C++和VC++之间的区别
  • Linux权限、用户以及文本处理的一些相关命令
  • git clone,git push,git pull
  • 对话巨杉核心研发团队:分布式数据库自研之路
  • 用NetHogs监控Linux每个进程的网络使用情况
  • 328
  • 学习Android的一些笔记
  • [PTA]数组循环右移
  • 国庆节
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 0基础学习移动端适配
  • KMP算法及优化
  • 从tcpdump抓包看TCP/IP协议
  • 回顾 Swift 多平台移植进度 #2
  • 你不可错过的前端面试题(一)
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 前端学习笔记之观察者模式
  • 前嗅ForeSpider中数据浏览界面介绍
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 世界上最简单的无等待算法(getAndIncrement)
  • python最赚钱的4个方向,你最心动的是哪个?
  • ​插件化DPI在商用WIFI中的价值
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #Spring-boot高级
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • ***详解账号泄露:全球约1亿用户已泄露
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .net 4.0发布后不能正常显示图片问题
  • .NET Core中的去虚
  • .net2005怎么读string形的xml,不是xml文件。
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • .NET性能优化(文摘)
  • @entity 不限字节长度的类型_一文读懂Redis常见对象类型的底层数据结构
  • [100天算法】-实现 strStr()(day 52)
  • [20171101]rman to destination.txt
  • [AMQP Connection 127.0.0.1:5672] An unexpected connection driver error occured
  • [bbk5179]第66集 第7章 - 数据库的维护 03
  • [C++]运行时,如何确保一个对象是只读的
  • [DAX] MAX函数 | MAXX函数
  • [Go WebSocket] 多房间的聊天室(三)自动清理无人房间
  • [HeMIM]Cl,[AeMIM]Br,[CeEIM]Cl,([HO-PECH-MIM]Cl,[HOOC-PECH-MIM]Cl改性酚醛树脂
  • [java基础揉碎]关系运算符(比较运算符)逻辑运算符赋值运算符三元运算符运算符的优先级
  • [LeetCode] Longest Common Prefix 字符串公有前序