问题描述
我有一个我的应用程序,其中包含一个部分,该部分将允许用户在屏幕上进行简单的绘画.我的想法是提供两种绘画方式:粗糙和平滑(贝塞尔曲线)线条.
I have this app of mine that contains a section that will allow the user to do simple paintings on the screen. My idea is to offer two kind of painting: rough and smooth (bezier) lines.
它是如何构建的:我有一个带有自定义drawRect方法的透明UIView.我不确定我是否完全理解drawRect,但是代码部分起作用.
How it is built: I have a transparent UIView with a custom drawRect method. I am not sure if I understood drawRect completely, but the code is partially working.
工作原理:用户在屏幕上移动手指.当他第一次触摸屏幕时,TouchesBegan会创建一个名为myPoints的可变数组,并存储第一个点的坐标,并按原样存储画布(以允许撤消).
How it works: the user moves the finger around the screen. When he first touches the screen, TouchesBegan creates a mutablearray called myPoints and store the coordinate of the first point and stores the canvas as it is (to allow undo).
之后,TouchesMoved例程将获取所有点并将其添加到myPoints中.如果用户选择绘制贝塞尔曲线,则需要此数组.
After that, TouchesMoved routine grabs all points and adds them to myPoints. This array is needed in the case the user chooses to draw bezier lines.
当检测到touchesEnded时,应用程序必须查看用户是绘制常规线条(粗糙)还是贝塞尔曲线.如果不是贝塞尔曲线,则已经绘制了线条.如果需要贝塞尔曲线,则需要擦除画布,恢复TouchesBegan存储画布时的画布,计算新的贝塞尔曲线近似值(反向工程为适合绘制点的最佳贝塞尔曲线),并绘制新曲线,取代粗糙的.
When touchesEnded is detected, the app has to see if the user was painting a regular line (rough) or a bezier. If it was not bezier, the lines are already drawn. If a bezier is needed, I need to erase the canvas, restore the canvas as it was when TouchesBegan stored it, calculate the new bezier approximation (reverse engineered to be the best bezier curve to fit the drawn points) and draw the new curve, replacing the rough one.
这些是我的问题:
1)如何存储撤消?我首先想到要创建一个新层来存储撤消,但是这样做会使应用程序的内存使用从8 Mb增加到13 Mb ...我不确定这是否可以安全使用(该应用程序与3GS,iPod兼容)触摸2nd G及更高版本(包括iPad).然后,我决定触发一个队列操作以保存画布.这导致保存空白图像(我想保存方法的上下文为nil,因为它无法在drawRect之外获得上下文).
1) How to store the undo? I first thought on creating a new layer to store the undo, but doing that increased the app memory usage from 8 to 13 Mb... I am not sure if this is a safe level to use (the app is compatible with 3GS, iPod Touch 2nd G, and up, including iPad). Then, I decided to fire a queue operation to save the canvas. This is resulting in blank images being saved (I suppose the saving method is getting nil for the context, because it cannot get the context outside the drawRect).
2)第二个问题类似于第一个问题.此时,我需要将画布还原到保存时的状态,但是由于restore方法在drawRect之外,因此它也变为零.
2) the second problem is similar to the first one. At this point I need to restore the canvas to what it was when it was saved, but as the restore method is outside the drawRect it it getting nil to the context too.
TouchesBegan,TouchesMoved和TouchesEnded以及提到的所有方法都在drawRect所在的同一个类中,而不是在viewController中.
TouchesBegan, TouchesMoved and TouchesEnded and all methods mentioned are inside the same class where the drawRect is, not in the viewController.
我的问题是:你们将如何做到这一点?
My questions is: how do you guys would do that?
我在商店看到一个绘画应用程序提供了多级撤消功能.我无法想象他们是如何做到的,因为在我的第一次尝试中,我创建的每一层都消耗了5 Mb的内存,因此似乎无法进行此类撤消...
I saw a painting app on the store offering multi level undo. I cannot imagine how they did that, because in my first try, for ever layer I created I was consuming 5 Mb of memory, so it appears impossible to have that kind of undos...
请帮帮我...我很绝望!
please, help me... I am desperate!
谢谢
推荐答案
为什么要存储画布"? (我认为那是您要绘制的图像吗?)
Any reason why are you storing the "canvas"? (I think that would be the image that you're drawing right?)
我认为您想要做的是将可绘制对象(粗线,贝塞尔曲线等)存储在某个对象中,该对象具有路径"中的所有点,然后您将具有一个所有对象的集合(即nsmutablearray)您的可绘制对象....然后drawRect接收该集合并将其绘制到屏幕上.
I think what you want to do is store the drawable objects (rough lines, bezier, etc.) in some object that has all the points in the "path" and you then have a collection (ie a nsmutablearray) with all your drawable objects.... then the drawRect takes that collection and draws it to the screen.
可以执行撤消操作,因此当用户要撤消操作时,可以从集合中删除最后一个可绘制对象,或者在集合中添加最后一个点,然后重绘...
Undo could be implemented so when the user wants to undo, you remove the last drawable object from the collection or the last point added to the collection and redraw...
您无法在drawRect之外获得绘图上下文,但是您所需要做的就是更新数据结构(点,可绘制对象等),并通过调用[self setNeedsDisplay]使控件无效",因此操作系统称您为drawRect,然后可以将对象绘制到屏幕上.
You cannot get the drawing context outside the drawRect, but all you need to do, is update your data structure (the points, drawable objects, etc.) and "invalidate" your control by calling [self setNeedsDisplay] so the OS call you're drawRect and then you can draw your objects onto the screen.
我创建了一个简单的概念验证应用程序(在c#winforms中.我现在无法访问我的mac,但足够简单,可以理解该概念),可以用这种方式工作.示例代码位于
I created a simple proof of concept app (is in c# winforms... I don't have access to my mac right now, but is simple enough to understand the concept) that works this way. The sample code is at
https://github.com/jaimedp/DrawEraseUndo
请注意,如果您变得更复杂,则此概念有几个局限性,例如,如果您根据手指移动的速度来看待线条的底线,尽管可以添加更多内容,但重绘不会处理此问题可绘制对象的属性以说明更多奇特之处.
Note that this concepts have several limitations if you get more complex, for example, if you get fancy with the withs of the lines depending on the speed of the finger movement, the redrawing does not handle this, although you could add more properties to the drawable object to account for more fanciness.
如果需要,我会将示例移植到iOS.
I'll port the sample to iOS if needed.
希望这会有所帮助.
这篇关于iPhone-试图找出drawRect:的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!