我是iOS开发的新手,我正在努力弄清楚CATiledLayer是如何工作的。而不是如何使用它!
CATiledLayer有两个关键特性,我想知道它是如何工作的。
CATiledLayer如何知道它的可见边界已经改变了?我可以创建一个自定义的CALayer并注册以知道相同的信息吗?我想了解这两个关键点是如何工作的原因是,我正在构建一个可以具有非常大宽度的自定义UIView,而CALayer会因为有这么大的后台层而崩溃。CATiledLayer有一个轻的内存使用和它‘几乎完美!
我不想使用CATiledLayer的原因是它是如何内部工作的。所有绘图都发生在后台线程上。我知道您甚至可以在主线程上调用绘图逻辑,但这将在下一个绘图周期发生。由于绘图不在同一绘制周期内进行,因此在视图大小调整期间,我们的绘图逻辑会延迟更新绘图,从而导致用户在更新过程中UIView内容发生抖动。
只是想多加一点。我正在构建一个音频编辑器,它显示音频波形,用户可以调整这个剪辑的大小。剪辑显示在集合视图中。以上提到的问题与CATiledLayer似乎是相同的问题车库乐队。我几乎没有注意到,当调整一个音频剪辑的左边。他们可能使用CATiledLayer。
发布于 2018-05-10 02:59:49
我知道一种解决第一问题的方法,但我不确定结果和效率。这是更多的理论,但它是可行的。我使用一个CADisplayLink来运行一个检查,看看该层的帧是否在主窗口中。我确实注意到使用了少量的CPU (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可能不使用子层,而是将所有内容缓慢地绘制到一个内容图像中,而是通过平铺和可能更简单的数学计算。它可能是将可见区域绘制在背景中并提供层内容的东西。然后缓存该部分并添加另一个部分,直到它是complete.This,这只是猜测。
这是我在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中设置的,所以我可以监视它。如果这有帮助的话请告诉我。此外,检查还可以修改框架,以便在它出现在屏幕上之前以一条空白的方式捕捉它,即在此之前绘制的方式。
https://stackoverflow.com/questions/50261060
复制相似问题