手绘板的制作——命令模式与撤销、重制(3)
前言
我们这篇来了解下撤销、重制的功能,其实也就是 undo 和 redo,在这里我们使用命令模式去设计,若对该模式不了解的话,可以考虑看下 「关于命令模式的误区,你知道了吗」。
其实对于命令模式,我最开始的理解为命令模式只是为了方便数据的管理和记录,不应该和具体的事务或状态进行绑定,后面经过跟同事的“友好”沟通后,感觉命令模式更符合数据的管理+具体事务执行
,这个这样才算是一个命令的独立执行过程,而并非只是对数据进行管理,后续的操作还得自己额外去执行。
好了,正文开始。
命令模式实践
首先,新建 ICommand 接口,由于 dart 没有 interface,就用 abstract class
进行代替:
abstract class ICommand{// 执行execute();// 撤销undo();
}
使用 Invoker 进行命令的管理:
class Invoker {// 存储命令内容late List<ICommand> _undoCommands = [];late List<ICommand> _redoCommands = [];/// 执行execute(ICommand command) {_undoCommands.add(command);command.execute();}/// 撤销undo() {if (_undoCommands.isNotEmpty) {final last = _undoCommands.last;_redoCommands.add(last);_undoCommands.remove(last);last.undo();}}/// 重制redo() {if (_redoCommands.isNotEmpty) {final last = _redoCommands.last;_undoCommands.add(last);_redoCommands.remove(last);last.execute();}}
}
关于 Invoker 的设计也是很简单,使用两个 List 去存储命令,分别是 undo 命令列表 和 redo 命令列表。然后执行 undo 和 redo 操作时,其实就是对两个命令列表的数据进行增删操作,同时调用该命令的执行或撤销。
至于具体的命令设计上,每一种操作都应该拥有一种具体的命令实现,由于我这里仅存储画笔的操作,所以我只封装一种命令:
class PaintedCommand extends ICommand {late Stroke _stroke;late PaintedBoardProvider _paintedBoardProvider;PaintedCommand(PaintedBoardProvider paintedBoardProvider, Stroke stroke) {_paintedBoardProvider = paintedBoardProvider;_stroke= stroke;}@overrideexecute() {if (!_paintedBoardProvider.strokes.contains(_stroke)) {_paintedBoardProvider.strokes.add(_stroke);}_paintedBoardProvider.refreshPaintedBoard();}@overrideundo() {if (_paintedBoardProvider.strokes.contains(_stroke)) {_paintedBoardProvider.strokes.remove(_stroke);}_paintedBoardProvider.refreshPaintedBoard();}
}
PaintedCommand 需要使用到 PaintedBoardProvider 和 Stroke,PaintedBoardProvider 用于数据与状态管理,Stroke 用于存储当前命令的数据,而 execute 和 undo 其实就是该命令运作时所需的操作,也就是数据管理+状态更新。
在这里用到了 PaintedBoardProvider 的 refreshPaintedBoard()
方法,其实就是 notifyListeners()
:
refreshPaintedBoard(){notifyListeners();}
到了这里有可能有人会问,你这画笔操作不是有两种吗?一种笔刷模式,一种橡皮擦模式,为什么只设计一种命令?
这是因为笔刷模式和橡皮擦模式的区分仅在于 Stroke 中 isClear 的值,所以为了便于管理,使用一种命令更合适。
场景运用
下面我们把刚刚设计好的命令模式应用到具体业务中。
首先,我们得新增两个按钮:undo 和 redo,并且新建 Invoker 对象进行操作 :
class _MyHomePageState extends State<MyHomePage> {final PaintedBoardProvider _paintedBoardProvider = PaintedBoardProvider();final Invoker _invoker = Invoker(); // <- 重点在这里
Expanded(child: GestureDetector(onTap: () {print("点击了 undo");_invoker.undo(); // <- 新增},child: const Center(child: Text("undo"),),),),Expanded(child: GestureDetector(onTap: () {print("点击了redo");_invoker.redo(); // <- 新增},child: const Center(child: Text("redo"),),),),
剩下的就是要确认命令执行时机。
正常来说,一旦画布进行更改了,就是一次命令,但是由于在手绘期间,画布是一直在不断刷新的,若是这样继续记录,那命令数量就过于庞大了,所以这里我该改为一次手势完整流程就是一次命令,这样我们可以在 onPanEnd
进行记录即可。
所以,我们先把 _invoker 传递给 HandPaintedBoard:
Expanded(child: HandPaintedBoard(_paintedBoardProvider, _invoker)), // <- 重点在这里
class HandPaintedBoard extends StatefulWidget {const HandPaintedBoard(this._paintedBoardProvider, this._invoker, { // <- 更改Key? key,}) : super(key: key);final PaintedBoardProvider _paintedBoardProvider;final Invoker _invoker; // <- 更改
然后在 onPanEnd
进行命令的执行:
onPanEnd: (details) {print("onPanDown:移动结束");widget._invoker.execute(PaintedCommand( // <- 命令执行_paintedBoardProvider, _paintedBoardProvider.strokes.last));},
由此,整个效果就完成了。
手绘板的制作——命令模式与撤销、重制(3)相关推荐
- 手绘板的制作——画布保存(6)
「手绘板的制作--手绘(1)」 「手绘板的制作--重置与橡皮擦(2)」 「手绘板的制作--命令模式与撤销.重制(3)」 「手绘板的制作--画布缩放(4)」 「手绘板的制作--画布移动(5)」 前言 经 ...
- 手绘板的制作——画布移动(5)
前言 在上文「手绘板的制作--画布缩放(4)」中,我们学会了画布的缩放,这节我们学习下画布的移动,毕竟放大的画布不能移动的话,那放大还有什么意义.=_= 手势检测 既然要移动,那当然需要检测手势,由于 ...
- 手绘板的制作——手绘(1)
前言 通过上一篇文章「如何优雅地画一张图」我们已经知道如何在画布里面绘画一张图了,这次我准备开一个系列讲解下手绘板的制作,可能包含: 手绘 橡皮擦 撤销 重制 重置 图片导出 命令模式 等功能.具体等 ...
- 手绘板的制作——画布缩放(4)
前言 在这一篇中,我们讲解下画布的缩放,也就是做一个根据手势缩放进行画布缩放的功能. 我们先来梳理下逻辑: 监听手势,当为一根手指的时候,就延续之前的操作,执行手绘操作,当操作为两根手指的时候,则执行 ...
- Android View与SurfaceView的手绘板制作
最近学习了如何使用View与SurfaceView制作简单的手绘板,在此做个小结. 自定义VIew实现手绘板: 首先是使用View来实现手绘板: package com.app.superxlcr.m ...
- java画图颜色_手绘板,多种颜色选择。我抄的《疯狂java讲义》的,包我乱导的,但代码能用。...
[java]代码库import javax.swing.*; import java.awt.image.*; import java.awt.datatransfer.*; import javax ...
- Photoshop---Wacom手绘板绘画画变成了拖动,根本不能画画
前述 以下步骤都是基于windows10上的结果,而且的确是解决了我的问题,windows7没有试过,估计差不多,分享出来希望能帮到众位仙家. 背景&问题 近段时间photoshop手绘的时候 ...
- 手绘线条一直画不直_手绘板线条画不直怎么办?板绘画线诀窍分享
在数位板画画和在纸上画画是有一定区别的,线条很难控制,手绘板线条画不直,那么如何在数位板上画出流畅线条?越是习惯手绘的朋友,那你可能就需要画更多的时间来适应数位板的画图方式,今天微课菌给大家分享一组板 ...
- 什么是数位板? 数位板,又名绘图板、绘画板、手绘板等等,是计算机输入设备的一种,通常是由一块板子和一支压感笔组成,它和手写板等作为非常规的输入产品相类似,都针对一定的使用群体。 与手写板所不同的是
什么是数位板? 数位板,又名绘图板.绘画板.手绘板等等,是计算机输入设备的一种,通常是由一块板子和一支压感笔组成,它和手写板等作为非常规的输入产品相类似,都针对一定的使用群体. 与手写板所不同的是,数 ...
最新文章
- java 简单万年历_JAVA实现的简单万年历代码
- norm--求矩阵和向量的范数
- HDU 1114(没有变形的完全背包)
- js控制a标签点击事件 触发下载
- 全国计算机等级考试题库二级C操作题100套(第82套)
- 数据类型的转换小结 c# 1614092651
- Java开发找工作最懵圈的问题:到底啥是分布式系统开发经验?
- ARM处理器与架构对应关系
- 基于卷积神经网络和迁移学习实现场景图片分类任务
- VS 2013安装教程
- 图像分割(多分类)将mask变为one hot label
- Html源码在线翻译,HTML – 谷歌翻译网站
- tomcat设置一级域名、二级域名访问指定项目
- 矩阵求逆的一万种方法
- 红色警戒2+尤里的复仇,带完整音乐+影片,免安装版本,完美兼容WIN10
- 郑州 - 天气总是灰蒙蒙的
- Yocto中WIC控制以及WKS文件
- 【秋钓皮皮】 奔跑吧,皮皮!(有图了)
- 二度云抢先成为首批工信部(.vip/.xyz/.club)域名注册管理机构
- 北航计算机就业2018,2020年考研:北京航空航天大学2018年的毕业生就业情况怎样?北航就业前景分析...
热门文章
- keil玩儿51单片机时遇见的错误与警告
- python多线程内存溢出_ThreadPoolExecutor使用后内存溢出(一)
- 分享7个素材网帮你轻松解决,新手做自媒体没播放?收益少?
- chrome android 分屏,谷歌调整安卓系统:分屏多任务同时支持两款以上APP!
- Ubuntu18.04使用静态ip
- 计算机图形(Cha.3 光栅化)
- 我是一名程序员,帮我写一篇年终述职报告
- 2020山东春季高考计算机专业,2020山东春季高考科目时间及总分
- OSChina 周四乱弹 —— 老公你回来啦?
- vue中使用excel单个/批量导出表格数据