UIBarButtonItem 动画时 UITableView 中的故障
Glitch in UITableView when UIBarButtonItem is animated
当成功 CloudKit 同步时,我使用第二个右侧栏按钮项目作为指示器。但是,如果当指示器出现时 tableView 处于滚动状态(项目现在位于导航栏下方),则 tableView 会与动画同步弹跳。如果用户没有与 tableView 交互,则不会发生这种情况。
这是演示效果的 GIF。
其他 UIBarButtonItem
已在情节提要中设置。我的 iCloud 同步指示器是在 viewDidLoad()
:
中的代码中设置的
var cloudIndicator = UIImageView()
cloudIndicator.frame = CGRect(x: 0, y: 0, width: 25, height: 25)
cloudIndicator.contentMode = .center
cloudIndicator.transform = CGAffineTransform.identity
// Get existing right bar button item which was set up in storyboard
var rightButtonItems = self.navigationItem.rightBarButtonItems ?? []
let customButtonItem = UIBarButtonItem(customView: cloudIndicator)
rightButtonItems.append(customButtonItem)
self.navigationItem.rightBarButtonItems = rightButtonItems
这是使云同步指示器动画化的方法:
func cloudLabelImageAlert(_ image: UIImage, tintColor: UIColor = .darkGray) {
DispatchQueue.main.async {
self.cloudIndicator.alpha = 0
self.cloudIndicator.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
self.cloudIndicator.tintColor = tintColor
self.cloudIndicator.image = image
// Animate icon appearing
UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 10, options: [], animations: {
self.cloudIndicator.alpha = 1
self.cloudIndicator.transform = CGAffineTransform.identity
}, completion: { didFinish in
// Animate icon disappearing
UIView.animate(withDuration: 0.4, delay: 2.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: [], animations: {
self.cloudIndicator.alpha = 0
self.cloudIndicator.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
}, completion: nil)
})
}
)
推测这个问题与动画过程中图像视图的框架变化有关,但奇怪的是它只发生在与tableView交互时。
有没有办法防止这种情况发生,或者有更好的方法将图像视图动画化为条形按钮项目?
编辑
感谢评论中的建议,原来是重载tableview的问题,与动画无关
我找到了有问题的代码,它在 CloudKit 同步后调用:
if let index = self.tableView.indexPathForSelectedRow {
self.tableView.deselectRow(at: index, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
self.tableView.reloadData() // This is delayed as it was causing problems with autoselection (e.g. after coming from Spotlight or notification)
let image = UIImage(named: "cloudTick")!
self.cloudLabelImageAlert(image, tintColor: self.colors[0])
}
} else {
self.tableView.reloadData()
let image = UIImage(named: "cloudTick")!
self.cloudLabelImageAlert(image, tintColor: self.colors[0])
}
注释掉 self.tableview.reloadData()
行停止了故障,但动画仍按预期继续。
此时我需要为用户更新数据。有更好的方法吗?
似乎出于某种神秘原因,您的导航栏暂时显示 "large title",这导致 tableView 的 contentInset 发生变化。
因此,请尝试在 viewDidLoad:
中完全手动禁用大标题
if #available(iOS 11.0, *) {
navigationItem.largeTitleDisplayMode = .never
navigationController?.navigationBar.prefersLargeTitles = false
}
如评论部分所述,您可能在加载新的 table 单元格时调用了 cloudLabelImageAlert(image:, tintColor:)
方法。
关于更新数据,我建议在云动画完成后调用table视图reloadData()
方法。
嗨,我有一些类似的故障,但对我来说,它通过在 viewDidLoad 中将 self.automaticallyScrollInsets 设置为 false 并在最终的 UIView.animate 完成块中为隐藏和显示动画 imageView 得到修复称为 reloadData()。希望这对您有所帮助,谢谢!
当成功 CloudKit 同步时,我使用第二个右侧栏按钮项目作为指示器。但是,如果当指示器出现时 tableView 处于滚动状态(项目现在位于导航栏下方),则 tableView 会与动画同步弹跳。如果用户没有与 tableView 交互,则不会发生这种情况。
这是演示效果的 GIF。
其他 UIBarButtonItem
已在情节提要中设置。我的 iCloud 同步指示器是在 viewDidLoad()
:
var cloudIndicator = UIImageView()
cloudIndicator.frame = CGRect(x: 0, y: 0, width: 25, height: 25)
cloudIndicator.contentMode = .center
cloudIndicator.transform = CGAffineTransform.identity
// Get existing right bar button item which was set up in storyboard
var rightButtonItems = self.navigationItem.rightBarButtonItems ?? []
let customButtonItem = UIBarButtonItem(customView: cloudIndicator)
rightButtonItems.append(customButtonItem)
self.navigationItem.rightBarButtonItems = rightButtonItems
这是使云同步指示器动画化的方法:
func cloudLabelImageAlert(_ image: UIImage, tintColor: UIColor = .darkGray) {
DispatchQueue.main.async {
self.cloudIndicator.alpha = 0
self.cloudIndicator.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
self.cloudIndicator.tintColor = tintColor
self.cloudIndicator.image = image
// Animate icon appearing
UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 10, options: [], animations: {
self.cloudIndicator.alpha = 1
self.cloudIndicator.transform = CGAffineTransform.identity
}, completion: { didFinish in
// Animate icon disappearing
UIView.animate(withDuration: 0.4, delay: 2.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0, options: [], animations: {
self.cloudIndicator.alpha = 0
self.cloudIndicator.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
}, completion: nil)
})
}
)
推测这个问题与动画过程中图像视图的框架变化有关,但奇怪的是它只发生在与tableView交互时。
有没有办法防止这种情况发生,或者有更好的方法将图像视图动画化为条形按钮项目?
编辑
感谢评论中的建议,原来是重载tableview的问题,与动画无关
我找到了有问题的代码,它在 CloudKit 同步后调用:
if let index = self.tableView.indexPathForSelectedRow {
self.tableView.deselectRow(at: index, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
self.tableView.reloadData() // This is delayed as it was causing problems with autoselection (e.g. after coming from Spotlight or notification)
let image = UIImage(named: "cloudTick")!
self.cloudLabelImageAlert(image, tintColor: self.colors[0])
}
} else {
self.tableView.reloadData()
let image = UIImage(named: "cloudTick")!
self.cloudLabelImageAlert(image, tintColor: self.colors[0])
}
注释掉 self.tableview.reloadData()
行停止了故障,但动画仍按预期继续。
此时我需要为用户更新数据。有更好的方法吗?
似乎出于某种神秘原因,您的导航栏暂时显示 "large title",这导致 tableView 的 contentInset 发生变化。
因此,请尝试在 viewDidLoad:
if #available(iOS 11.0, *) {
navigationItem.largeTitleDisplayMode = .never
navigationController?.navigationBar.prefersLargeTitles = false
}
如评论部分所述,您可能在加载新的 table 单元格时调用了 cloudLabelImageAlert(image:, tintColor:)
方法。
关于更新数据,我建议在云动画完成后调用table视图reloadData()
方法。
嗨,我有一些类似的故障,但对我来说,它通过在 viewDidLoad 中将 self.automaticallyScrollInsets 设置为 false 并在最终的 UIView.animate 完成块中为隐藏和显示动画 imageView 得到修复称为 reloadData()。希望这对您有所帮助,谢谢!