Постоянно анимированный вид в Swift - PullRequest
0 голосов
/ 03 июля 2018

Я создаю подкласс AVPlayerController, который наблюдает за игроком и управляет состояниями игрока. Если AVPlayerItemStatus равно .failed, я добавляю пользовательский UIView поверх фрейма игрока. В настоящее время важные части кода моего пользовательского представления выглядят так:

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()
    } 
}

Я вызываю метод animate() из другого ViewController, который хранит объект NoiseView.

Дело в том, что он работает так, как и должен работать (представление анимируется и создает белый шум), но приложение начинает работать медленно. Каким должен быть правильный подход к перерисовке представления, не вызывая такого снижения производительности?

Кстати, падение произошло с интервалом 0,1 с (10 FPS). Чего я хочу добиться, так это иметь постоянный белый шум с частотой не менее 30 кадров в секунду, чтобы он выглядел как настоящий телевизионный шум.

Ответы [ 3 ]

0 голосов
/ 03 июля 2018

Вместо использования таймера и вызова setNeedsDisplay, что в результате будет вызывать метод рисования, что приведет к замедлению работы приложения.

Используйте CAAnimation и создайте слой CALayer или CAreplicator и анимируйте его.

Если вам нужен код, вы можете проверить эту ссылку Color Picker или я могу опубликовать демо-код через некоторое время, его время: -p.

CAReplicatorlayer CALayer

0 голосов
/ 03 июля 2018

Существует ряд стратегий, которые вы можете попытаться оптимизировать, используя код для рисования, но для меня наиболее очевидным является то, что вы должны предварительно рассчитать необходимые CGRect вне кода для рисования.

Для запускаемых вами циклов требуется * итераций каждого кадра анимации для расчета всех необходимых CGRect. Это много и совершенно не нужно, потому что CGRect всегда будут одинаковыми, если ширина и высота неизменны. Вместо этого вы должны сделать что-то вроде этого:

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()
}

Предварительно кешируя тезисы, вам нужно всего лишь сделать (w * h) количество итераций, что является огромным улучшением.

Если этого недостаточно для повышения производительности, вы можете дополнительно оптимизировать, используя аналогичные стратегии предварительного кэширования, например, вместо того, чтобы рандомизировать каждый пиксель, предварительно рассчитать листы случайных цветов вне кода прорисовки и затем случайным образом собрать их в drawRect(). Если проблема с производительностью связана с рандомизатором, это приведет к сокращению объема работы.

Ключевая стратегия состоит в том, чтобы попытаться минимизировать объем работы, которую должен выполнять ваш метод drawRect(), поскольку он выполняется в каждом кадре анимации.

Удачи!

0 голосов
/ 03 июля 2018

Пользовательские draw(rect:) методы могут привести к снижению производительности.

Я предлагаю добавить CAAnimation или CAAnimationGroup к вашему виду белого шума.

CABasicAnimation Documentation

CAAnimationGroup StackOverflow Post

...