下面的代码通过覆盖触摸来绘制线条,但是在连续不间断的绘制期间开始出现滞后。手指在屏幕上移动的时间越长,这种滞后就会越积越多。结果是实际设备上的 CPU 几乎达到最大值(CPU 98% ),并且绘制的时间越长,生成的图像就越不稳定。
此外,当画得特别快时,尤其是在圆圈中,在
1 - 如何消除连续绘制一段时间的滞后延迟?
2 - 如何消除绘制路径的差异?
3 - 如何更改

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | var strokeColor = UIColor.blueColor() var lineWidth: CGFloat = 5 var snapshotImage: UIImage? private var path: UIBezierPath? private var temporaryPath: UIBezierPath? private var points = [CGPoint]() var counterPoints:Int? required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func drawRect(rect: CGRect) { autoreleasepool { snapshotImage?.drawInRect(rect) strokeColor.setStroke() path?.stroke() temporaryPath?.stroke() } } override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { let touch: AnyObject? = touches.first points = [touch!.locationInView(self)] counterPoints = 0 } override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { let touch: AnyObject? = touches.first let point = touch!.locationInView(self) points.append(point) let pointCount = points.count counterPoints = counterPoints! + 1 if pointCount == 2 { temporaryPath = createPathStartingAtPoint(points[0]) temporaryPath?.addLineToPoint(points[1]) setNeedsDisplay() } else if pointCount == 3 { temporaryPath = createPathStartingAtPoint(points[0]) temporaryPath?.addQuadCurveToPoint(points[2], controlPoint: points[1]) setNeedsDisplay() } else if pointCount == 4 { temporaryPath = createPathStartingAtPoint(points[0]) temporaryPath?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2]) // setNeedsDisplay() if counterPoints! < 50 { self.setNeedsDisplay() } else { temporaryPath = nil self.constructIncrementalImage() path = nil self.setNeedsDisplay() counterPoints = 0 } } else if pointCount == 5 { points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0) // create a quad bezier up to point 4, too if points[4] != points[3] { let length = hypot(points[4].x - points[3].x, points[4].y - points[3].y) / 2.0 let angle = atan2(points[3].y - points[2].y, points[4].x - points[3].x) let controlPoint = CGPoint(x: points[3].x + cos(angle) * length, y: points[3].y + sin(angle) * length) temporaryPath = createPathStartingAtPoint(points[3]) temporaryPath?.addQuadCurveToPoint(points[4], controlPoint: controlPoint) } else { temporaryPath = nil } if path == nil { path = createPathStartingAtPoint(points[0]) } path?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2]) self.setNeedsDisplay() points = [points[3], points[4]] } } override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { self.constructIncrementalImage() path = nil self.setNeedsDisplay() counterPoints = 0 } override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { self.touchesEnded(touches!, withEvent: event) } private func createPathStartingAtPoint(point: CGPoint) -> UIBezierPath { let localPath = UIBezierPath() localPath.moveToPoint(point) localPath.lineWidth = lineWidth localPath.lineCapStyle = .Round localPath.lineJoinStyle = .Round return localPath } private func constructIncrementalImage() { UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0) strokeColor.setStroke() snapshotImage?.drawAtPoint(CGPointZero) path?.stroke() temporaryPath?.stroke() snapshotImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() } } |
你问过:
How can the lagging latency over a period of continuous drawing be eliminated?
正如您正确推测的那样,是的,创建快照并重置路径可以通过限制路径的长度来解决此问题。
我知道您已经意识到这一点,但为了其他读者的利益,在 iOS 9 中您也可以使用预测性触控。在这个特定的算法中(其中(a)您只是添加到路径,但(b)每四个点根据下一个点进行调整,以确保两条三次贝塞尔曲线连接处没有不连续性)有点棘手,但可以做到。
How can the discrepancy in the paths drawn be eliminated?
这是因为快照包含临时路径。但是该临时路径的全部目的是随着更多点的进入,它将被丢弃。因此,您不应将其包含在您创建的中间手势快照中。
所以,我建议在快照函数中添加一个参数,指示是否应包含
例如:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | var strokeColor = UIColor.blueColor() var lineWidth: CGFloat = 20 var snapshotImage: UIImage? private var path: UIBezierPath? private var temporaryPath: UIBezierPath? private var points = [CGPoint]() private var totalPointCount = 0 override func drawRect(rect: CGRect) { snapshotImage?.drawInRect(rect) strokeColor.setStroke() path?.stroke() temporaryPath?.stroke() } override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { let touch: AnyObject? = touches.first points = [touch!.locationInView(self)] totalPointCount = totalPointCount + 1 } override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { let touch: AnyObject? = touches.first let point = touch!.locationInView(self) points.append(point) totalPointCount = totalPointCount + 1 updatePaths() if totalPointCount > 50 { constructIncrementalImage(includeTemporaryPath: false) path = nil totalPointCount = 0 } setNeedsDisplay() } private func updatePaths() { // update main path while points.count > 4 { points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0) if path == nil { path = createPathStartingAtPoint(points[0]) } path?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2]) points.removeFirst(3) } // build temporary path up to last touch point let pointCount = points.count if pointCount == 2 { temporaryPath = createPathStartingAtPoint(points[0]) temporaryPath?.addLineToPoint(points[1]) } else if pointCount == 3 { temporaryPath = createPathStartingAtPoint(points[0]) temporaryPath?.addQuadCurveToPoint(points[2], controlPoint: points[1]) } else if pointCount == 4 { temporaryPath = createPathStartingAtPoint(points[0]) temporaryPath?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2]) } } override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { constructIncrementalImage() path = nil temporaryPath = nil setNeedsDisplay() } override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { touchesEnded(touches!, withEvent: event) } private func createPathStartingAtPoint(point: CGPoint) -> UIBezierPath { let localPath = UIBezierPath() localPath.moveToPoint(point) localPath.lineWidth = lineWidth localPath.lineCapStyle = .Round localPath.lineJoinStyle = .Round return localPath } private func constructIncrementalImage(includeTemporaryPath includeTemporaryPath: Bool = true) { UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0) strokeColor.setStroke() snapshotImage?.drawAtPoint(CGPointZero) path?.stroke() if (includeTemporaryPath) { temporaryPath?.stroke() } snapshotImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() } } |
顺便说一句,虽然我是提供路径生成代码的人,但我意识到它可以简化一点。我也修复了一个错误。见上面的代码。
然后你问:
How can the alpha/opacity of the path and temporaryPath be changed?
您可以使用适当的 alpha 调整调用
2 3 4 5 6 7 8 9 | snapshotImage?.drawInRect(rect) strokeColor.setStroke() path?.stroke() strokeColor.colorWithAlphaComponent(0.5).setStroke() temporaryPath?.stroke() } |
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
是否可以在所有delayed_job任务之前运行一个方法?基本上,我们试图确保每个运行delayed_job的服务器都有我们代码的最新实例,所以我们想运行一个方法来在每个作业运行之前检查它。(我们已经有了“check”方法并在别处使用它。问题只是关于如何从delayed_job中调用它。) 最佳答案 现在有一种官方方法可以通过插件来做到这一点。这篇博文通过示例清楚地描述了如何执行此操作http://www.salsify.com/blog/delayed-jobs-callbacks-and-hooks-in-rails(本文中描述
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上
我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia
我有这样的HTML代码:Label1Value1Label2Value2...我的代码不起作用。doc.css("first").eachdo|item|label=item.css("dt")value=item.css("dd")end显示所有首先标记,然后标记标签,我需要“标签:值” 最佳答案 首先,您的HTML应该有和中的元素:Label1Value1Label2Value2...但这不会改变您解析它的方式。你想找到s并遍历它们,然后在每个你可以使用next_element得到;像这样:doc=Nokogiri::HTML(
我构建了一个简单的银行应用程序,它能够执行通常的操作;充值、提现等我的Controller方法执行这些操作并拯救由帐户或其他实体引发的异常。以下是Controller代码中使用的一些方法:defopen(type,with:)account=createtype,(holders.findwith)addaccountinit_yearly_interest_foraccountboundary.renderAccountSuccessMessage.new(account)rescueItemExistError=>messageboundary.rendermessageendde
我有一个允许更新用户记录的表单。它包含:password和:password_confirmation字段,但我不希望在数据库中已存储加密密码时对它们运行验证。View文件中的字段:'ConfirmPassword'%>在互联网上搜索时,我发现了这段代码,我认为它是针对以前版本的Ruby/Rails的。(我会把它放在我的用户模型中。)validates_presence_of:password,:on=>create由于我的用户模型中密码验证的语法不同(如下),我对我需要的语法感到困惑。validates:password,:presence=>true,:confirmation=>