我正在尝试为移动设备(Android)编写一个绘画应用程序,它将具有比MS Paint更多的功能(例如各种画笔和画笔设置,选择,图层),但不会像Photoshop那样复杂。我需要我的应用程序有一个不错的撤消/重做功能。可能无法进行无限制的撤消/重做。我很高兴能够撤消最后一分钟的用户操作(可能大约20个操作)。
我知道撤消/重做的主要方法是:
保存整个状态或仅保存每次操作后更改的位。撤消涉及通过还原快照来更新状态。优点:易于实现缺点:内存密集型。
使用命令模式,其中每个命令都有“执行操作”和“撤消操作”方法。要撤消,只需调用上一个命令的撤消操作即可。优点:内存效率高,缺点:实现起来要复杂得多。
我必须考虑的病态撤消/重做场景是:
用户一次性绘制整个画布,您希望在用户单击撤消时撤消整个操作。使用选项1,我们需要存储整个画布大小的位图。
用户绘制内容,将图像1.jpg导入到画布上,做更多绘图,然后由另一个应用程序在某个时刻删除/修改1.jpg然后用户想要撤消然后重做所有他们的涂料应用程序中的操作。我真的不确定如何在撤销堆栈中保存任何导入图像的副本时在这里正确撤消。
任何人都可以提供有关如何在内存和处理器速度较低的移动设备上最佳实施撤消/重做的任何建议吗?我喜欢简单的1和3,但似乎唯一现实的选择是2.我不知道如何用这个选项来应对我的第二个病态例子。
答案 0 :(得分:2)
在iPhone上,Core Data内置了对undo和redo的支持。只需使您的数据模型反映绘制的对象,您就可以轻松地在保存之间前后滚动。通常,您将保存用于创建图形的过程和对象,而不是图形本身。
好的,但这只是一个小API 支持实施2号和2号 对我给出的例子没有帮助。
使这项工作的关键想法是,您不要将数据模型配置为模态并保留程序的图形输出,将其配置为 模态并保持过程 创建图形输出。
创建图形程序的简单方法是设置数据流,如:
Input_UI-->Display_UI-->Data_Model
用户操纵Input_UI,它直接改变Display_UI的屏幕图形。只有当用户保存时,Data_Model才会起作用。这种类型的数据流使得undo / redo(和其他东西)很难实现,特别是在绘画中,例如合成程序。每个操作都必须知道如何撤消自身,并且必须能够对更改的图形进行操作。
更好的方法是设置这样的数据流:
Input_UI-->Data_Model-->Display_UI
用户操纵Input_UI,该Input_UI与操作用户选择的Data_Model通信。 Data_Model记录过程,例如“在rect {0,0,100,100}添加文件jpg.1”。对Data_Model的更改向Display_UI发送通知,该通知读取已更改的数据并实现所描述的过程。
Data_Model将自身回滚,Display_UI只是绘制Data_Model告诉它的内容。 Display_UI根本不需要了解撤消过程。
在绘图程序中,您将创建单个图形对象的逻辑层,以便重做只是按照添加它们的相反顺序删除图层。对于绘画/合成程序,您必须从最后一个保存点开始,然后重新创建图形,直到最后一步。
因此,在您的合成程序示例中:
解决这个问题的方法是忽略GUI,而是考虑如何设计一个从命令行运行的应用程序,而不使用任何GUI输入或输出。 Data_Modal的工作原理相同。它将保存文本命令和数据(例如导入的图像)以创建输出图像,而不仅仅是屏幕上图像的快照。
答案 1 :(得分:1)
我喜欢简单的1和3但是 这似乎是唯一现实的 选项是2。
我不确定“3”是什么,因为你的问题似乎只有两个选项。
关于#1的内存消耗,如果你使用内存,这只是一个问题。只有在AsyncTask
(或可能是常规后台线程处理LinkedBlockingQueue
)将它们写入SD卡时,才能保留在内存中的历史记录。没有SD卡 - 没有撤消/重做。在撤消时,如果您的历史记录已将其写入磁盘,请从磁盘重新加载。只需确保清理SD卡(在干净的出口处删除历史记录,在下次启动时删除所有延迟文件)。
请记住,我从未编写过绘画应用程序,更不用说在Android上了,因此可能存在性能问题(例如,撤消可能需要一秒钟才能从SD卡中加载位图)。