Как CATiledLayer работает внутри - PullRequest
0 голосов
/ 09 мая 2018

Я новичок в разработке для iOS и пытаюсь понять, как работает CATiledLayer. НЕ как это использовать!

Есть две ключевые особенности CATiledLayer Я хочу знать, как это работает.

  1. Видимые границы автоматической отчетности. Как CATiledLayer узнает, что его видимые границы изменились? Могу ли я создать пользовательский CALayer и зарегистрироваться, чтобы узнать ту же информацию?

  2. Чертеж плитки. Как нарисованы эти плитки? Они нарисованы как подслои?

Причина, по которой я хочу выяснить, как работают эти две ключевые точки, заключается в том, что я создаю пользовательский UIView, который может иметь очень большую ширину и CALayer потерпит крах из-за наличия такого большого слоя подложки. CATiledLayer имеет небольшое использование памяти и почти идеален!

Причина, по которой я не хочу использовать CATiledLayer, заключается в том, как она работает внутри. Все рисование происходит в фоновом потоке. Я знаю, что можно даже вызвать логику рисования в главном потоке, но это произойдет в следующем цикле рисования. Поскольку рисование не происходит в одном и том же цикле рисования, во время изменения размера представления наша логика рисования имеет задержку при обновлении чертежей, в результате чего содержимое UIView дрожит во время обновлений пользователем.

Просто добавлю немного больше к этому. Я создаю аудио редактор, где он показывает звуковую форму волны, и пользователь может изменить размер этого клипа. Клип показан внутри представления коллекции. Упомянутая выше проблема с CATiledLayer, похоже, та же проблема, что и у Garage band. Я едва могу заметить это при изменении размера аудиоклипа влево. Они, вероятно, используют CATiledLayer.

1 Ответ

0 голосов
/ 10 мая 2018

Я знаю один способ ответить на вопрос номер один, но я не уверен в последствиях и эффективности. Это более теоретически, но это работает. Я использую CADisplayLink для запуска проверки, чтобы увидеть, находится ли рамка слоя в главном окне. Я заметил небольшое использование процессора (1% или меньше), поэтому я бы протестировал его больше, чем CATiledLayer. CATiledLayer просто разбивает чертеж, но работает на той же предпосылке, что можно нарисовать только то, что видно. drawRect Я думаю, что в основном работает, когда видимые или видимые границы меняются. Что касается подкласса, который я тестировал, я использовал его внутри UICollectionView и знаю, что он работает. Я мог даже получить журналы, когда ячейка была создана, а не на экране. Вот рабочий подкласс CALayer. Я не знаю, поможет ли это вам, но это возможно.

import UIKit
protocol OnScreenLayerDelegate:class {
    func layerIsOnScreen(currentScreenSpace:CGRect)
    func layerIsNotOnScreen(currentScreenSpace:CGRect)
}
class OnScreenLayer: CALayer {

    var displayLink : CADisplayLink?
    weak var onScreenDelegate : OnScreenLayerDelegate?
    override init() {
        super.init()
        commonSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonSetup()
    }

    func commonSetup(){
        displayLink = CADisplayLink(target: self, selector: #selector(checkOnScreen))
        displayLink?.add(to: .main, forMode: .commonModes)
    }

    @objc func checkOnScreen(){
        if let window = UIApplication.shared.keyWindow{
            let currentRect = self.convert(self.bounds, to: window.layer)
            if window.bounds.intersects(currentRect){
                onScreenDelegate?.layerIsOnScreen(currentScreenSpace: currentRect)
            }else{
                onScreenDelegate?.layerIsNotOnScreen(currentScreenSpace: currentRect)
            }
        }
    }
}

Что касается вопроса 2, я думаю, что CATiledLayers, вероятно, не использует подслои и вместо этого медленно рисует все содержимое в одно изображение содержимого, но с помощью листов и, вероятно, более легкой математики для них. Это может быть что-то, что берет видимую область, рисует это на заднем плане и обеспечивает содержание слоя. Затем кэширует этот раздел и добавляет другой, пока он не будет завершен. Это только предположение.

Вот код из моего теста в ячейке collectionView.

import UIKit

class AlbumCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var imageView: UIImageView!
    var onScreenLayer = OnScreenLayer()
    var currentIndex : Int = 0
    override func awakeFromNib() {
        super.awakeFromNib()
        onScreenLayer.frame = self.bounds
        self.layer.addSublayer(onScreenLayer)
        onScreenLayer.onScreenDelegate = self
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        onScreenLayer.frame = self.bounds
    }
}

extension AlbumCollectionViewCell : OnScreenLayerDelegate{
    func layerIsOnScreen(currentScreenSpace: CGRect) {
        //or more proof
         print("it is on screen \(currentIndex)")

    }

    func layerIsNotOnScreen(currentScreenSpace: CGRect) {
        print("not on screen \(currentIndex)")
    }
}

Текущий индекс был установлен в cellForItem, чтобы я мог его отслеживать. Позвольте мне знать, если это помогает. Кроме того, проверка может изменить рамку, чтобы поймать ее прямо перед тем, как она появится на экране с полями, которые вы рисуете до этого.

...