I use the second right bar button item as an indicator when there is a successful CloudKit sync. However, if the tableView is held in scroll (with items now under the navigation bar) when the indicator appears, the tableView bounces in sync with the animation. This does not happen if the user is not interacting with the tableView.
Here is a GIF demonstrating the effect.
The other UIBarButtonItem
s are set up in the storyboard. The one for my iCloud sync indicator is set up in code in 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
This is the method that animates the cloud sync indicator:
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)
})
}
)
Presumably this problem relates to the frame of the image view changing during the animation, but it seems strange that it only happens while the tableView is being interacted with.
Is there a way to prevent this happening, or a better way to animate an image view as a bar button item?
Edit
Thanks to advice in the comments, it turns out this is due to reloading the tableview and nothing to do with the animation.
I found the problematic code, which is called after a CloudKit sync:
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])
}
Commenting out the self.tableview.reloadData()
lines stopped the glitch but the animation continued as expected.
I need to update the data at this point for the user. Is there a better way to do this?