ios - Swift 中的持续动画 View

标签 ios swift animation draw

我正在创建 AVPlayerController 的子类,它观察播放器并处理播放器的状态。如果 AVPlayerItemStatus.failed,我会在播放器的框架上添加一个自定义的 UIView。目前,我的自定义 View 代码的重要部分如下所示:

class NoiseView: UIView {

    ...

    var timer: Timer?
    func animate() {
        timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
    }

    func stopAnimating() {
        timer?.invalidate()
    }

    @objc func timerAction() {
        self.setNeedsDisplay()
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        let context = UIGraphicsGetCurrentContext()!
        let h = rect.height
        let w = rect.width

        var val: CGFloat!
        var color: UIColor!

        for i in 0...Int(w-1) {
            for j in 0...Int(h-1) {
                val = .random
                color = UIColor(red: val, green: val, blue: val, alpha: 1.0)

                context.setFillColor(color.cgColor)
                context.fill(CGRect(x: i, y: j, width: 1, height: 1))
            }
        }

        context.flush()
    } 
}

我正在从保留 NoiseView 对象的其他 ViewController 调用方法 animate()

问题是,它按预期工作( View 正在动画并产生白噪声)但应用程序开始运行缓慢。在不导致此类性能下降的情况下重绘 View 的正确方法应该是什么?

顺便说一句,下降发生在 0.1s 间隔(10 FPS)。我想要完成的是拥有至少 30 FPS 的恒定白噪声,看起来像合法的电视噪声。

最佳答案

您可以尝试多种策略来优化绘图代码,但对我来说最明显的一个是您应该在绘图代码之外预先计算您需要的 CGRects。

您正在运行的循环需要对每个动画帧 进行 w^h 次迭代,以计算您需要的所有 CGRect。这很多,而且完全没有必要,因为只要宽度和高度不变,CGRects 就会始终相同。相反,您应该这样做:

var cachedRects = [CGRect]()
override var frame: CGRect {
    didSet {
        calculateRects()
    }
}

func calculateRects() {
    cachedRects = []
    let w = frame.width
    let h = frame.height
    for i in 0...Int(w-1) {
        for j in 0...Int(h-1) {
            let rect = CGRect(x: i, y: j, width: 1, height: 1)
            cachedRects += [rect]
        }
    }
}

override func draw(_ rect: CGRect) {
    super.draw(rect)
    let context = UIGraphicsGetCurrentContext()!
    var val: CGFloat!
    var color: UIColor!
    for rect in cachedRects {
        val = .random
        color = UIColor(red: val, green: val, blue: val, alpha: 1.0)
        context.setFillColor(color.cgColor)
        context.fill(rect)
    }
    context.flush()
}

通过预缓存 rects,您只需执行 (w * h) 次迭代,这是一个巨大的改进。

如果这还不足以提高性能,您可以使用类似的预缓存策略进一步优化,例如不是随机化每个像素,而是在绘制代码之外预先计算随机颜色的图 block ,然后将它们随机组合到drawRect()。如果随机发生器是性能问题所在,这将减少它必须要做的工作量。

关键策略是尽量减少 drawRect() 方法必须完成的工作量,因为它在每一帧动画上运行。

祝你好运!

关于ios - Swift 中的持续动画 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51159813/

相关文章:

ios - UITableViewCell 已选择 subview 背景颜色已更改

ios - 在 iOS 中为我​​自己的框架添加 "THIS has been renamed to THAT"

swift - 如何在带有范围的for循环中向后迭代

ios - (快速)当 AudioStreamPacketDescription 为 nil 时调试 CrashIfClientProvidedBogusAudioBufferList 的方法?

javascript - jQuery Mobile - 单击后 PreventDefault 后的按钮样式

ios - 斯威特4。初始 ViewController 一瞬间错误,然后修复

ios - SWIFT:var someVariable:int = textfield.text.toInt() x textfield2.text.toInt() 并强制展开

javascript - 使用 ng-repeat 在 AngularJS 中鼠标悬停时激活 .gif

WPF 事件触发器不起作用

android - 为每个数据条目在一行上显示带有按钮的数据