使用 Quartz 2D 的简单 iPhone 绘图应用程序

发布于 2024-08-01 19:20:59 字数 827 浏览 8 评论 0原文

我正在制作一个简单的 iPhone 绘图程序作为个人业余项目。

我在子类 UIView 中捕获触摸事件并将实际内容渲染到单独的 CGLayer。 每次渲染后,我调用 [self setNeedsLayout] 并在 drawRect: 方法中将 CGLayer 绘制到屏幕上下文。

这一切都非常有效,并且在绘制矩形时表现良好。 然而,我只想要一个简单的“徒手”模式,就像许多其他 iPhone 应用程序一样。

我想到的方法是创建一个 CGMutablePath,很简单:

CGMutablePathRef path;
-(void)touchBegan {
    path = CGMutablePathCreate();
}
-(void)touchMoved {
    CGPathMoveToPoint(path,NULL,x,y);
    CGPathAddLineToPoint(path,NULL,x,y);

}
-(void)drawRect:(CGContextRef)context {
      CGContextBeginPath(context);
      CGContextAddPath(context,path);
      CGContextStrokePath(context);
}

但是,绘制超过 1 秒后,性能会严重下降。

如果不是可变的不透明度,我会将每条线绘制到离屏 CGLayer 中! 低于 100% 的不透明度会导致屏幕上留下连接线条的点。 我看过 CGContextSetBlendingMode() 但可惜我找不到答案。

有人能指出我正确的方向吗? 其他 iPhone 应用程序能够以非常高的效率做到这一点。

I am making a simple iPhone drawing program as a personal side-project.

I capture touches event in a subclassed UIView and render the actual stuff to a seperate CGLayer. After each render, I call [self setNeedsLayout] and in the drawRect: method I draw the CGLayer to the screen context.

This all works great and performs decently for drawing rectangles. However, I just want a simple "freehand" mode like a lot of other iPhone applications have.

The way I thought to do this was to create a CGMutablePath, and simply:

CGMutablePathRef path;
-(void)touchBegan {
    path = CGMutablePathCreate();
}
-(void)touchMoved {
    CGPathMoveToPoint(path,NULL,x,y);
    CGPathAddLineToPoint(path,NULL,x,y);

}
-(void)drawRect:(CGContextRef)context {
      CGContextBeginPath(context);
      CGContextAddPath(context,path);
      CGContextStrokePath(context);
}

However, after drawing for more than 1 second, performance degrades miserably.

I would just draw each line into the off-screen CGLayer, if it were not for variable opacity! The less-than-100% opacity causes dots to be left on the screen connecting the lines. I have looked at CGContextSetBlendingMode() but alas I cannot find an answer.

Can anyone point me in the right direction? Other iPhone apps are able to do this with very good efficiency.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

家住魔仙堡 2024-08-08 19:20:59

问题是,使用 CGStrokePath() 时,当前的可变路径会被关闭并绘制,并且当您移动手指时会创建一条新路径。 因此,您最终可能会得到很多用于一键“会话”的路径,至少您的伪代码似乎是这样做的。

您可以尝试在触摸开始时开始新的可变路径,在触摸移动时使用 CGAddLineToPoint() ,并在触摸结束时结束路径(很像伪代码所示)。 但是在绘制方法中,您绘制了当前可变路径的副本,并且实际的可变路径仍然被拉长,直到触摸结束,因此您在整个触摸会话中只能获得一条路径。 触摸结束后,您可以永久添加路径 - 例如,您可以将所有路径放入数组中并在绘制方法中迭代它们。

The problem is that with CGStrokePath() the current mutable path gets closed and drawn and a new path is created when you move your finger. So you probably end up with a lot of paths for one touch "session", at least that's what your pseudocode seems to do.

You can try to begin a new mutable path when touches begin, use CGAddLineToPoint() when the touches move und end the path when touches end (much like your pseudocode shows). But in the draw method, you draw a copy of the current mutable path, and the actual mutable path is still being elongated until the touches end, so you only get one path for the whole touch session. After the touches end you can add the path permanently - you can for example put all paths into an array and iterate over them in the draw method.

如梦 2024-08-08 19:20:59

SanHolo 所说的 - 另外,您可能想限制点的添加,因此它只会添加一个新点,频率不超过每 10 毫秒(您需要调整间隔)。 您可以使用一个简单的计时器来做到这一点。

另外,您如何指示视图需要重绘自身? 您可能也想对其进行限制 - 并且它的间隔可能比点捕获更长(例如,捕获点不超过每 10 毫秒,重绘频率不超过每 200 毫秒 - 同样,您需要处理这些数字) 。

在这两种情况下,您都需要确保,如果在捕获最后一个点的时间间隔内没有发生任何事情,或者请求重绘。 这就是计时器发挥作用的地方。

What SanHolo said - plus you may want to throttle the adding of points, so it only adds a new point no more often than every 10ms, say (you'd need to play with the interval). You can do that with a simple timer.

Also, how are you instructing the view that it needs to redraw itself? You might want to throttle that too - and it could be on a longer interval than the point capturing (e.g. capture points no more than every 10ms, and redraw no more often than every 200ms - again you'd need to play with the numbers).

In both cases you'd need to make sure that, if nothing happens for longer than the interval the last point is captured, or the redraw is requested. That's where the timer comes in.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文