CATiledLayer如何在内部工作

时间:2018-05-09 19:52:18

标签: ios objective-c uiview calayer catiledlayer

我是iOS开发的新手,我试图找出CATiledLayer的工作原理。不是如何使用它!

CATiledLayer有两个关键功能我想知道它是如何工作的。

  1. 可见边界自动报告。 CATiledLayer如何知道它的可见边界已经改变了?我可以创建自定义CALayer并注册以了解相同的信息吗?

  2. 瓷砖绘图。这些瓷砖是如何绘制的?它们是作为子图层绘制的吗?

  3. 我想知道这两个关键点如何工作的原因是我构建了一个宽度非常大的自定义UIView,而CALayer会因为有CATiledLayer而崩溃这么大的后备层。 CATiledLayer具有轻量内存使用率及其使用权限。几乎完美!

    我不想使用UIView的原因是它在内部如何运作。所有绘图都在后台线程上进行。我知道你甚至可以在主线程上调用绘图逻辑,但这会在下一个绘图周期中发生。由于绘图不会在同一个绘制周期中发生,因此在视图调整大小期间,绘图逻辑会延迟更新绘图,从而导致CATiledLayer内容在用户更新期间抖动。

    只是为此添加一点。我正在构建一个音频编辑器,用于显示音频波形,用户可以调整此剪辑的大小。剪辑显示在集合视图中。上面提到的问题CATiledLayer似乎与Garage乐队的问题相同。在将音频剪辑调整到左侧时,我几乎无法注意到它。他们可能正在使用$MasterServerConnString = dbserver,1433 #********************************************************************** #region Get Server List #Get Server list from SQL DB Table and save to temp Powershell table #********************************************************************** $ping_cmd = "Set NOCOUNT ON; SELECT distinct machinename, IS_PINGABLE FROM [DB].[dbo].[TABLE] order by 1" $ping_cn = new-object System.Data.SqlClient.SqlConnection("Data Source=$MasterServerConnString;Integrated Security=SSPI;Initial Catalog=DB"); $ping_cn.Open() $ping_a = $ping_cn.CreateCommand() $ping_a.CommandText = $ping_cmd $ping_a = $ping_a.ExecuteReader() $ping = new-object “System.Data.DataTable” "computername" $ping.Load($ping_a) $ping_cn.Close() $Server = $ping.Item(0) #********************************************************************** #endregion #********************************************************************** #region Ping Sever Test #Ping each server to see if there is connectivity. If pingable, 1. If not pingable 0. #********************************************************************** $PCData = foreach ($PC in $Server) { Write-Verbose "Checking computer'$PC'" try { Test-Connection -ComputerName $PC -Count 2 -ErrorAction Stop | Out-Null $Props = @{ ComputerName = $PC Status = 1 } New-Object -TypeName PSObject -Property $Props } catch { # either ping failed or access denied try { Test-Connection -ComputerName $PC -Count 2 -ErrorAction Stop | Out-Null $Props = @{ ComputerName = $PC Status = 0 } New-Object -TypeName PSObject -Property $Props } catch { $Props = @{ ComputerName = $PC Status = 0 } New-Object -TypeName PSObject -Property $Props } } } #********************************************************************** #endregion #********************************************************************** #region Upload Results #Upload the ping results for each server back to the database table #********************************************************************** foreach ($sv in $PCData) { $svr_name = $sv.ComputerName $svr_stat = $sv.Status $Updatequery = " Update [DB].[dbo].[TABLE] SET IS_PINGABLE = $svr_stat WHERE MachineName = '$svr_name' " $A_cn = new-object System.Data.SqlClient.SqlConnection("Data Source=$MasterServerConnString;Integrated Security=SSPI;Initial Catalog=DB"); $A_cn.Open() $command = $A_cn.CreateCommand() $command.CommandText = $Updatequery $result = $command.ExecuteReader() $A_cn.Close() } #********************************************************************** #endregion

1 个答案:

答案 0 :(得分:0)

我知道一种方法可以做第一个问题,但我不确定后果和效率。除了有效之外,这更具理论性。我正在使用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可能不会使用子图层,而是慢慢地将所有内容绘制到单个内容图像中,但是通过平铺并可能更容易计算它们。它可能是可见区域在后台绘制它并提供图层内容的东西。然后缓存该部分并添加另一部分直到它完成。这只是猜测。

这是我在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中设置,因此我可以对其进行监控。如果这有帮助,请告诉我。此外,检查可以修改框架,以便在它进入屏幕之前通过您之前绘制的边距捕获它。