There's a strange bounce when my app is run on iPhone 14 Pro (and Pro Max) models but not any other models. How can I remove it?
The source code is here: https://github.com/ykphuah/ListBouncePro
Refer to the video below. Left is the iPhone 14 simulator, while right is the iPhone 14 pro simulator. There's a bounce on the main listing after the sheet is dismissed.
First, the reason the issue seems to be related to CoreData
is because this implementation causes the table view to update while it is covered by the presented controller.
You can easily confirm this by triggering a reload while the Edit controller is presented:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "edit") {
if let indexPath = tableView.indexPathForSelectedRow {
let controller = (segue.destination as! UINavigationController).topViewController as! EditController
controller.isNew = false
controller.shopping = frc?.object(at: indexPath)
tableView.deselectRow(at: indexPath, animated: false)
// add this to trigger a reload after 1 second (while the presented controller is still showing)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
self.tableView.reloadData()
})
} else {
let controller = (segue.destination as! UINavigationController).topViewController as! EditController
controller.isNew = true
}
}
}
Now, even if you only tap "Cancel" the gap will be there.
And, you can confirm this by setting up:
With this as the entire code:
class NoCoreDataTableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "defCell", for: indexPath)
c.textLabel?.text = "\(indexPath)"
return c
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: indexPath, animated: false)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
self.tableView.reloadData()
})
}
}
}
When run, pulling down the presented controller shows the gap:
and the gap remains after pulling it down far enough to dismiss it.
The only thing I've found that seems reliable is to implement scrollViewDidChangeAdjustedContentInset(...)
and adjust the table view's .contentInset.top
to "fix" the incorrect inset.
If you add this to your ListController
class:
// class property
var origTopInset: CGFloat = 0
override func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView) {
if origTopInset == 0 {
origTopInset = scrollView.adjustedContentInset.top
}
if scrollView.adjustedContentInset.top != origTopInset {
scrollView.contentInset.top = -abs(origTopInset - scrollView.adjustedContentInset.top)
}
}
that should get rid of the gap / bounce. If the app is running on a different device (such as iPhone 14 (non-Pro) from your original post), the .adjustedContentInset.top
won't change, and so this work-around code won't adversely affect anything.
Note that I've only done cursory testing -- so thoroughly test this yourself.
Edit
The above .adjustedContentInset.top
"fix" only works if the row updates are set to .none
instead of .fade
...
I've re-updated my repo clone: https://github.com/DonMag/ListBouncePro with a "Closures" branch for another approach.
I had seen cases where it still failed, but I didn't realize that Core Data calls didChange
when the object changes ... such as:
shopping?.item = textField.text
I was under the impression it did not occur until:
appDelegate.saveContext()
I've re-posted my clone of your repo: https://github.com/DonMag/ListBouncePro with a "Closures" branch.
The changes are:
indexPath
if an item was selected, or nil
if "+" newAll Core Data functions then take place in the List controller, which solves the "bouncing" / gap.
Now the tableView updating takes place after the presented controller is dismissed. That might be considered a drawback ... or maybe not. Since the data is being sorted, the user may find this easier to follow when seeing the update, rather than returning to a re-ordered list.
As a side note -- this may be more effort than it's worth, and may not be completely compatible with the rest of your data handling.
Frankly, the "bounce" is - to me - a non-issue. And, since this is pretty clearly a bug that will hopefully be corrected in an iOS update, any work put in to work around it would eventual be unnecessary (and maybe even counter-productive).
However, take a look at the "Closure" branch and see what you think... you might even decide that using your Edit controller only for editing and not for actual data updating is a better approach all around.