【问题标题】:Laggy UITableView scrolling because of CAShapeLayer (Swift 3)由于 CAShapeLayer (Swift 3) 而导致 UITableView 滚动延迟
【发布时间】:2017-07-17 05:22:55
【问题描述】:

我在 UIView 中有一个 UITableView,它由以下类定义的自定义单元格组成:

class CustomAddFriendTableViewCell: UITableViewCell {
    @IBOutlet weak var UsernameLbl: UILabel! 
    @IBOutlet weak var ProfileImg: UIImageView!
    @IBOutlet weak var AddFriendBtn: UIButton!
}

在 ViewController 的 tableview(_:cellForRowAt:) 方法中,我调用以下函数来布局单元格的 ProfileImg:

private func layoutProfilePics(with cell:CustomAddFriendTableViewCell) {
    //create gradient
    let gradient = CAGradientLayer()
    gradient.frame =  CGRect(origin: CGPoint.zero, size: cell.ProfileImg.frame.size)
    gradient.colors = [Colors.blueGreen.cgColor, Colors.yellow.cgColor]

    //create gradient mask
    let shape = CAShapeLayer()
    shape.lineWidth = 3
    shape.path = UIBezierPath(ovalIn: cell.ProfileImg.bounds).cgPath // commenting this out makes lag go away
    shape.strokeColor = UIColor.black.cgColor // commenting this out makes lag go away
    shape.fillColor = UIColor.clear.cgColor
    gradient.mask = shape

    cell.ProfileImg.layoutIfNeeded()
    cell.ProfileImg.clipsToBounds = true
    cell.ProfileImg.layer.masksToBounds = true
    cell.ProfileImg.layer.cornerRadius = cell.ProfileImg.bounds.size.width/2.0
    cell.ProfileImg.layer.addSublayer(gradient)

}

此代码使ProfileImg 成为一个圆圈,并具有蓝绿色渐变的边框。 旁边带有 cmets 的两条线使滚动非常平滑(这意味着渐变不是导致滞后的原因),所以我假设渲染 CAShapeLayer(特别是笔划)会导致问题(因此是问题标题)。我能做些什么来提高 tableview 的滚动性能?

另外,我不确定这是 XCode 错误还是与我的问题有关,但是在 Project Navigator 的 Instruments 窗格中,当我运行应用程序并滚动滞后的 UITableView 时,FPS 没有反映滞后,尽管我可以清楚地看出它非常滞后。事实上,窗格中的任何组件(CPU、内存、能源影响等)都没有明显差异。

更新:

我尝试将layoutProfilePics(with:) 函数移动到CustomAddFriendTableViewCellprepareForReuse() 函数中,我还尝试将layoutProfilePics(with:) 放入它的layoutSubviews() 函数中,但它们都没有改善滚动。

【问题讨论】:

  • 您应该更改tableview(_:cellForRowAt:) 中的内容。你的这种方法在创建单元格时是一个很好的选择,而不是在出队时。
  • 我尝试将函数移动到自定义单元格类的 layoutSubviews() 函数,并尝试将其移动到自定义单元格类的 prepareForReuse() 函数,但都没有提高 tableivew 的滚动性能。
  • 您是否确保只将这些图层添加到每个单元格一次?请记住,单元格会被重复使用,并且您在第一次使用时添加到单元格的任何层在重复使用时仍然存在,除非您将其删除。
  • @robmayoff 该方法在tableview(_:cellForRowAt:)中被调用,并且一个可重用的单元格在该tableview函数中出列,因此每次创建一个单元格时,其头像通过layoutProfilePics(with:)函数布局.由于 layoutProfilePics(with:) 函数仅在一个位置 (tableview(_:cellForRowAt:)) 调用,因此没有理由为同一个单元格多次调用它。即使重新加载 tableview 的数据,也会重新创建每个单元格,并且将为每个单元格调用一次布局函数。
  • 编辑您的问题以包含您的tableView(_:cellForRowAt:) 源代码。

标签: swift uitableview cashapelayer


【解决方案1】:

该代码应为每个单元格调用一次,因此不应在tableView(_:cellForRowAt:) 中调用它。尝试将该代码移至awakeFromNib(),如果您为自定义单元格使用笔尖,请使用viewDidLoad() 中的以下代码加载插座:

let addFriendCellNib = UINib(nibName: "CustomAddFriendTableViewCell", bundle: nil)
tableView.register(addFriendCellNib, forCellReuseIdentifier: "addFriendCell")

我希望这对你有用。

【讨论】:

  • 这行得通。谢谢!另外,您知道为什么仪器在延迟时没有显示您通常看到的任何数据吗?
  • 不确定您指的是什么数据。滞后是由于您的 UI 在滚动期间变得相当大;每次单元格出列时添加一个层。
  • 我指的数据是 XCode 中 Project Navigator Pane 中第 6 个选项卡上的 CPU 性能、FPS、内存等。你所说的相当大是什么意思?
  • 如果这就是您的意思,我正在获取 CPU 和内存基准值。相当大,我的意思是你正在向ProfileImg 添加子层,几秒钟后,动画开始变得迟钝。如果您打印子层数,它会不断增加,从而使您的 UI 复杂且庞大。
  • 哦,有道理。是的,我的意思是 CPU 和 FPS 基准值并没有反映我在滚动时看到的延迟。它们看起来很正常(例如,它说我获得了大约 60 FPS,尽管我可以看出滚动时有很多延迟)。
猜你喜欢
  • 1970-01-01
  • 2015-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多