动画自定义UITableViewCell

时间:2018-02-22 10:04:29

标签: ios swift uitableview uiviewanimation

我的应用程序架构存在问题......

我的UITableView填充了自定义UITableViewCells。 当然,我使用dequeuing所以只生成了8-10个单元格实例。

继续我的问题...我已经在我的应用程序中添加了主题功能。 当用户长时间触摸主UINavigationBar时,会在应用范围内发布通知,通知每个viewController更新其UI。

当托管带有自定义单元格的tableView的viewController收到通知时,它会调用tableView.reloadData()

这很有效,因为我实施了func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)

willDisplay内部,我在自定义tableViewCell上调用一个方法,该方法使用UIViewAnimation对单元格进行适当的颜色更改。

看起来像这样:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let newsFeedItemCell = cell as? NewsFeedItemCell {
        if (self.nightModeEnabled) {
            newsFeedItemCell.transitionToNightMode()
        } else {
            newsFeedItemCell.transitionFromNightMode()
        }
    }
}

在自定义单元格实现中,这些方法如下所示:

func transitionToNightMode() {
        UIView.animate(withDuration: 1, animations: {
            self.backgroundColor = UIColor.black
            self.titleTextView.backgroundColor = UIColor.black
            self.titleTextView.textColor = UIColor.white
        })
}

func transitionFromNightMode() {
    UIView.animate(withDuration: 1, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
}

这很好......继承人的问题:

在滚动tableView时,屏幕上没有任何单元格的颜色更新/动画代码会在滚动到屏幕上时显示为 ,这会导致一种刺耳的用户体验。

我理解为什么会发生这种情况,因为willDisplay仅在单元格显示时被调用。

我无法想出一种避免这种情况的优雅方法。

我很高兴屏幕上的细胞为用户体验带来愉悦的动画,但是,对于屏幕外的细胞,我宁愿他们跳过动画。

可能的解决方案(虽然不优雅):

保持对cellForRow创建的每个8-10个单元格的引用,并检查它们是否在屏幕外,如果它们立即设置其状态。

但是,我不喜欢保持对每个细胞的引用。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

我不会使用reloadData来设置动画,因为tableview的数据模型实际上并没有改变。

相反,我会给UITableView一个函数,如下所示:

class myClass : UITableViewController {
    ....

    func transitionToNightMode() {
            for visible in visibleCells {
            UIView.animate(withDuration: 1, animations: {
                visible.backgroundColor = UIColor.black
                visible.titleTextView.backgroundColor = UIColor.black
                visible.titleTextView.textColor = UIColor.white
            })
            }
    }
}

然后在你的willDisplay或cellForItemAt中,设置没有动画的正确外观。

答案 1 :(得分:1)

我会尝试以下方法。

UIView.animate中,我会创建一个transition(To/From)NightMode对象来代替使用UIViewPropertyAnimator。我会保留对该对象的引用,然后准备重用,如果动画仍在运行,我只需完成该动画并重置状态。所以像这样:

fileprivate var transitionAnimator: UIViewPropertyAnimator?

fileprivate func finishAnimatorAnimation() {
    // if there is a transitionAnimator, immediately finishes it
    if let animator = transitionAnimator {
        animator.stopAnimation(false)
        animator.finishAnimation(at: .end)
        transitionAnimator = nil
    }
}

override func prepareForReuse() {
    super.prepareForReuse()
    finishAnimatorAnimation()
}

func transitionToNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.black
        self.titleTextView.backgroundColor = UIColor.black
        self.titleTextView.textColor = UIColor.white
    })
    transitionAnimator?.startAnimation()
}

func transitionFromNightMode() {
    transitionAnimator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut, animations: {
        self.backgroundColor = UIColor.white
        self.titleTextView.backgroundColor = UIColor.white
        self.titleTextView.textColor = UIColor.black
    })
    transitionAnimator?.startAnimation()
}