Я знаю один способ ответить на вопрос номер один, но я не уверен в последствиях и эффективности. Это более теоретически, но это работает. Я использую 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, чтобы я мог его отслеживать. Позвольте мне знать, если это помогает. Кроме того, проверка может изменить рамку, чтобы поймать ее прямо перед тем, как она появится на экране с полями, которые вы рисуете до этого.