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()。希望这对您有所帮助,谢谢!