我的应用程序架构存在问题......
我的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个单元格的引用,并检查它们是否在屏幕外,如果它们立即设置其状态。
但是,我不喜欢保持对每个细胞的引用。
有什么想法吗?
答案 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()
}