- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我试图了解 Swift 中的不同绘图方法以及它们为何如此执行。
下面的代码使用 UIBezierPath
绘制平滑的线条,项目可从 https://github.com/limhowe/LimSignatureView 获得
最初,当用户开始触摸屏幕时,下面代码的性能是高度响应的。然而,随着时间的推移,在屏幕上触摸和移动的时间越长,性能开始滞后,显示的绘图跟不上并且不准确(似乎遗漏了一些点)。只有在触摸屏幕结束并再次开始触摸屏幕以进行新绘图时,性能才会恢复到高度响应。
我注意到的事情:
当self.setNeedsDisplay()
被注释掉时(在override func touchesMoved
),触摸屏幕时不显示绘图,但是一旦抬起手指触发override func touchesEnded
,最终的结果是完美的绘制,无论持续多长时间都没有滞后或不准确的绘制点。 (这是理想情况下想要并在绘图时显示的结果。)
当 beizerPath.removeAllPoints()
被注释掉(在 override func touchesEnded
中)时,即使在用户抬起手指并开始触摸再次筛选。
似乎 beizerPath.removeAllPoints()
可能会重置滞后,而 self.setNeedsDisplay()
可能会随着时间的推移导致滞后。
当将 beizerPath.lineWidth
从 2 增加到更大的宽度(例如 50 或 100)时,绘图往往会略微滞后。
嗯。我很困惑为什么一切都是这样。
随着时间的推移,这里到底发生了什么?
beizerPath.removeAllPoints()
和self.setNeedsDisplay()
和滞后有什么关系?
为什么增加 beizerPath.lineWidth
会导致一些轻微的延迟?
还有什么可能导致滞后?
在绘制时删除一些点是否可以提高性能?如果可以,如何实现?
下面的代码需要修改什么地方才能保证完美绘制持续超时不卡顿?
感谢对代码的任何开明反馈和改进。谢谢。
// LimSignatureView.swift
// SwiftSignatureView
//
// Created by MyAdmin on 3/6/15.
// Copyright (c) 2015 MyAdmin. All rights reserved.
//
import UIKit
class LimSignatureView: UIView {
var beizerPath: UIBezierPath = UIBezierPath()
var incrImage : UIImage?
var points : [CGPoint] = Array<CGPoint>(count: 5, repeatedValue: CGPointZero)
var control : Int = 0
var lblSignature : UILabel = UILabel()
var shapeLayer : CAShapeLayer?
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
incrImage?.drawInRect(rect)
beizerPath.stroke()
// Set initial color for drawing
UIColor.redColor().setFill()
UIColor.redColor().setStroke()
beizerPath.stroke()
}
override init(frame: CGRect) {
super.init(frame: frame)
var lblHeight: CGFloat = 61.0
self.backgroundColor = UIColor.blackColor()
beizerPath.lineWidth = 2.0
lblSignature.frame = CGRectMake(0, self.frame.size.height/2 - lblHeight/2, self.frame.size.width, lblHeight);
lblSignature.font = UIFont (name: "HelveticaNeue-UltraLight", size: 30)
lblSignature.text = "Sign Here";
lblSignature.textColor = UIColor.lightGrayColor()
lblSignature.textAlignment = NSTextAlignment.Center
lblSignature.alpha = 0.3;
self.addSubview(lblSignature)
}
// MARK : - TOUCH Implementation
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
if lblSignature.superview != nil {
lblSignature.removeFromSuperview()
}
control = 0;
var touch = touches.anyObject() as UITouch
points[0] = touch.locationInView(self)
var startPoint = points[0];
var endPoint = CGPointMake(startPoint.x + 1.5, startPoint.y
+ 2);
beizerPath.moveToPoint(startPoint)
beizerPath.addLineToPoint(endPoint)
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
var touch = touches.anyObject() as UITouch
var touchPoint = touch.locationInView(self)
control++;
points[control] = touchPoint;
if (control == 4)
{
points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0);
beizerPath.moveToPoint(points[0])
beizerPath.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2])
self.setNeedsDisplay()
points[0] = points[3];
points[1] = points[4];
control = 1;
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
self.drawBitmapImage()
self.setNeedsDisplay()
beizerPath.removeAllPoints()
control = 0
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
self.touchesEnded(touches, withEvent: event)
}
// MARK : LOGIC
func drawBitmapImage() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0);
if incrImage != nil {
var rectpath = UIBezierPath(rect: self.bounds)
UIColor.clearColor().setFill()
rectpath.fill()
}
incrImage?.drawAtPoint(CGPointZero)
//Set final color for drawing
UIColor.redColor().setStroke()
beizerPath.stroke()
incrImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
最佳答案
它变得迟钝的原因有两个。
首先,您在触摸事件中进行绘图。这被认为不是一个好主意。我同意这是获得最干净的触摸运动跟踪的最佳方法,但如果您关心性能,那绝对不是一个好主意。
其次,您要绘制每个移动事件的整个路径(从触摸到向上)。因此,即使您在到达第四段时已经绘制了前三段,您也可以清除屏幕并再次绘制前三段。这与每次触摸事件发生的绘图相结合会导致严重的减速。
理想情况下,您会将最新的触摸事件缓存到一个对象中。然后创建一个计时器(可能是 60 fps?)并从最后一个计时器事件到当前缓存的触摸位置画一条线。这可能会导致线条无法紧密跟随触摸事件,但您可能需要尝试一下。
然后通过该优化,您应该绘制到图像上下文中,然后在需要时将该上下文绘制到屏幕上。这样,您只将最新的段绘制到上下文中,而不是重新绘制整个路径。
这两件事应该可以极大地提高您的表现。它肯定会对跟踪触摸事件的清晰度产生不利影响,但你应该能够在某处找到一个快乐的媒介。也许您缓存了所有触摸事件,然后在计时器事件上将所有最新点绘制到上下文中并将该上下文填充到屏幕上。那么您应该能够保持跟踪的清晰度并提高性能。
您还可以研究在屏幕上的 UIImageView 内绘制 UIImage。这可能会保留您的历史绘制路径,而不需要您每次都重新绘制它,但我没有这方面的经验。
关于ios - 使用 Swift for iOS 绘制 UIBezierPath 随着时间推移的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32829778/
有没有办法在 .swift 文件(编译成 .swift 模块)中声明函数,如下所示: 你好.swift func hello_world() { println("hello world")
我正在尝试使用 xmpp_messenger_ios 和 XMPPFramework 在 iOS 上执行 MUC 这是加入房间的代码。 func createOrJoinRoomOnXMPP()
我想在我的应用程序上创建一个 3D Touch 快捷方式,我已经完成了有关快捷方式本身的所有操作,它显示正确,带有文本和图标。 当我运行这个快捷方式时,我的应用程序崩溃了,因为 AppDelegate
我的代码如下: let assetTag = Expression("asset_tag") let query2 = mdm.select(mdm[assetTag],os, mac, lastRe
我的 swift 代码如下所示 Family.arrayTuple:[(String,String)]? = [] Family.arrayTupleStorage:String? Family.ar
这是我的 JSON,当我读取 ord 和 uniq 数据时出现错误 let response2 : [String: Any] = ["Response":["status":"SUCCESS","
我想将 swift 扩展文件移动到 swift 包中。但是,将文件移动到 swift 包后,我遇到了这种错误: "Type 'NSAttributedString' has no member 'ma
使用CocoaPods,我们可以设置以下配置: pod 'SourceModel', :configurations => ['Debug'] 有什么方法可以用 Swift Package Manag
我正在 Xcode 中开发一个 swift 项目。我将其称为主要项目。我大部分都在工作。我在日期选择器、日期范围和日期数学方面遇到了麻烦,因此我开始了另一个名为 StarEndDate 的项目,其中只
这是 ObjectiveC 代码: CCSprite *progress = [CCSprite spriteWithImageNamed:@"progress.png"]; mProgressBar
我正在创建一个命令行工具,在 Xcode 中使用 Swift。我想使用一个类似于 grunt 的配置文件确实如此,但我希望它是像 Swift 包管理器的 package.swift 文件那样的快速代码
我假设这意味着使用系统上安装的任何 swift 运行脚本:#!/usr/bin/swift 如何指定脚本适用的解释器版本? 最佳答案 Cato可用于此: #!/usr/bin/env cato 1.2
代码说完全没问题,没有错误,但是当我去运行模拟器的时候,会出现这样的字样: (Swift.LazyMapCollection (_base:[ ] 我正在尝试创建一个显示报价的报价应用。 这是导入
是否可以在运行 Swift(例如 Perfect、Vapor、Kitura 等)的服务器上使用 RealmSwift 并使用它来存储数据? (我正在考虑尝试将其作为另一种解决方案的替代方案,例如 no
我刚开始学习编程,正在尝试完成 Swift 编程书中的实验。 它要求““编写一个函数,通过比较两个 Rank 值的原始值来比较它们。” enum Rank: Int { case Ace = 1 ca
在您将此问题标记为重复之前,我检查了 this question 它对我不起作用。 如何修复这个错误: error: SWIFT_VERSION '5.0' is unsupported, suppo
从 Xcode 9.3 开始,我在我的模型中使用“Swift.ImplicitlyUnwrappedOptional.some”包裹了我的字符串变量 我不知道这是怎么发生的,但它毁了我的应用程序! 我
这个问题在这里已经有了答案: How to include .swift file from other .swift file in an immediate mode? (2 个答案) 关闭 6
我正在使用 Swift Package Manager 创建一个应用程序,我需要知道构建项目的配置,即 Debug 或 Release。我试图避免使用 .xcodeproj 文件。请有人让我知道这是否
有一个带有函数定义的文件bar.swift: func bar() { println("bar") } 以及一个以立即模式运行的脚本foo.swift: #!/usr/bin/xcrun s
我是一名优秀的程序员,十分优秀!