我有一个缓冲区,每1/10秒就会填充一个浮点数据点。当数据准备就绪(每次大约4000个)时,我将该数据转换为行。
我在这里的问题,正如您可能已经知道的那样,绘图变得非常慢。我在下面发布了一些代码。
这是我的自定义UIView。这个方法被调用一次。
override func layoutSubviews() {
super.layoutSubviews()
// init stuff for drawing animation
path = UIBezierPath()
yOff = Float(self.bounds.height / 2)
lastPoint = CGPoint(x: 1.0, y: Double(yOff))
path.move(to: lastPoint)
path.addLine(to: lastPoint)
pathLayer = CAShapeLayer()
pathLayer.frame = CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height)
pathLayer.path = path.cgPath
pathLayer.strokeColor = UIColor.red.cgColor
pathLayer.fillColor = nil
pathLayer.lineWidth = 0.2
pathLayer.lineJoin = kCALineJoinBevel
let pathAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = 0.1
pathAnimation.fromValue = NSNumber(value: 0.0)
pathAnimation.toValue = NSNumber(value:1.0)
self.layer.addSublayer(pathLayer)
pathLayer.add(pathAnimation, forKey: "strokeEnd")
}
以下方法执行实际绘图,由" setNeedsDisplay"每1/10秒。
override func draw(_ rect: CGRect) {
// this is where the magic (animation) happens
CATransaction.begin()
pathLayer.path = path.cgPath
CATransaction.commit()
}
这是在viewcontroller中。我循环遍历数据点,为每个数据创建一个CGPoint。可能效率低下;欢迎任何帮助/想法:
for _s in samples
{
let currP = CGPoint(x: cX * xModifier, y: yOffSet + (CGFloat(_s)*yModifier))
cX += xLen
self.waveView.path.addLine(to: currP)
ctr = ctr + 1
}
DispatchQueue.main.async {
self.waveView.setNeedsDisplay()
}
提前致谢。
答案 0 :(得分:1)
有几点想法:
请勿更新draw
中的图层。您应该完全消除该方法,因为它只在您抚摸自己的路径时使用。但是你正在使用CAShapeLayer
,这就不需要做任何事了。更新路径后,请将对setNeedsDisplay
的呼叫替换为仅直接更新pathLayer.path
的代码。如果你想要制作动画,那么也可以在这里CABasicAnimation
执行。
与您当前的问题无关,您应该注意在layoutSubviews
中添加图层。该方法可以被多次调用。也许你现在只看到一次叫它,但可以反复调用它。例如,如果您旋转设备,它可以被调用。如果您使用autolayout,并执行触发autolayout引擎的操作,则可以调用它。作为一般规则,它可以被多次调用(即使你现在只看到它只调用一次)。
向路径添加4000个线段非常多,渲染速度很慢。从您的问题来看,您添加另外4000个线段的频率并不完全清楚。
通常当我们想要添加到现有(可能很长)的贝塞尔曲线路径时,我们会拍摄现有视图的快照,在UIImageView
中渲染,然后只渲染路径的增量部分CAShapeLayer
。这确保了一致的性能模式,只是渲染图像和增量部分的时间,而不是尝试重新渲染越来越长的UIBezierPath
。