iOS:在willDisplayCell中进行动画制作时,UITableView加速会变慢

时间:2016-09-08 18:18:55

标签: ios swift uitableview uikit core-animation

最新编辑: 经过一些更多的实验,我确信我遇到了触摸处理问题 我创建了一个自定义单元格,其子视图填充了内容视图宽度的一半。我正在为该子视图设置动画而不是内容视图。

Cell with Half view

在触摸单元格右侧的同时滚动桌面视图可正常工作 滚动单元格左侧的表格视图(动画视图所在的位置)会导致滞后。

修改 最后,我尝试做类似to this one的动画。 该问题中接受的答案与我提出的问题相同。 下面的代码是最简单的代码,可以重现这个问题。

dequeCellForIndexPath而不是willDisplayCell中制作动画没有任何区别。

willDisplayCell中进行动画制作时,表格视图滚动动画会变慢。当您尝试在tableview中快速滚动时,滚动会失去加速度。

一些重现问题的示例代码:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var tableView: UITableView!

    func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

        cell.contentView.layer.opacity = 0.0

        UIView.animateWithDuration(0.3) {
            cell.contentView.layer.opacity = 1.0
        }
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = UITableViewCell()

        cell.textLabel?.text = "\(indexPath.row)"

        return cell
    }


    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 300
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5000
    }
}

当电池的高度很大时,问题变得更糟。

无论如何要避免这种情况,还是有更好的功能来进行细胞动画?

相关:Blogpost on doing animations like this

编辑2: GIF说明了这个问题:

在所有3个案例中,我都在手机上尽可能快地滚动。

在willDisplayCell中使用动画我到达第60行

Using Animation

没有动画我到达第400行

Normal Scrolling

在willDisplayCell中随机延迟0到0.3秒之间,阻止主队列,我到达第120行

Laggy Scrolling

我想某处的触控处理存在问题。

即使the library I use to visualize how fast I'm scrolling,在willDisplayCell中使用动画时也会中断。

3 个答案:

答案 0 :(得分:2)

尝试在tableView.dequeueReusableCellWithIdentifier(..)功能中使用cellForRowAtIndexPath。我尝试了下面的代码,滚动性能看起来很好。我还添加了cell.contentView.layer.removeAllAnimations()以在单元格消失后取消动画。

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCellWithIdentifier(identifier) as? TableViewCell else { fatalError("where's my cell") }
    cell.textLabel?.text = "\(indexPath.row)"
    return cell
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 300
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 5000
}

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    cell.contentView.layer.opacity = 0.0
    UIView.animateWithDuration(0.3) {
        cell.contentView.layer.opacity = 1.0
    }
}

override func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    cell.contentView.layer.removeAllAnimations()
}

答案 1 :(得分:1)

所以,你当然应该将细胞出列而不是一直重新创建细胞。在您的测试中,不会产生太多差异,但随着您的细胞变得越来越复杂,它将会发挥作用。

此外,您需要考虑何时使用动画,以及动画应该有多大。有一个原因是集合视图上的股票动画仅适用于要添加的项目 - 因为它是动画的有效使用。通常,当用户向上滚动时,这些项目不是新的,因此单元格中滚动到视图中的任何动画都是一个令人困惑的范例。

现在,当向下滚动时,我可以看到为什么你可能想要动画。在这种情况下你需要考虑滚动速度 - 如果你滚动然后动画很难/不可能看到,所以没有意义这样做......

因此,跟踪滚动速度。在简单的选项中,如果您滚动速度超过某个阈值速度,那么就不要进行动画处理。在复杂选项中调整动画的大小以获得滚动速度,因此慢速滚动仍然具有大部分动画,并且动画中的滚动速度更快,直到达到该阈值并且关闭所有动画。

答案 2 :(得分:0)

正如其他人所说,首先你必须将一个单元格出列而不是每次都初始化一个单元格。

如果您使用AutoLayout进行细胞布局,我建议将其删除如果没有其他工作。 (这是一个很棒的功能,但它也需要很多CPU时间。)

但我的解决方案是解决方法,不要使用UIViewAnimation。请改用UIScrollViewDelegate。在scrollViewDidScroll方法中,获取tableView的可见单元格并设置最后一个单元格的alpha,方法是直接计算它与屏幕底部的距离,而不需要任何动画。