iOS 11 UITableViewCell above viewForHeaderInSection view after deleting - ios

I have simple UITableViewController.
View for header. Which inits from xib.
And single type of cell.
After deleting cell with swipe, cell which above deleted one become visible above HeaderView, when other cells just hides below HeaderView as it should be.
If something above not clear - ask.
Video: https://youtu.be/aX-iPnM3q4Q

I think this should solve it:
tableView.sendSubview(toFront: tableView.headerView(forSection: 0)!)
(assuming you have only 1 section)
You can set this after deleting the cell, for example in commitEditingStyle.

Found the solution.
func deleteItem(from indexPath: IndexPath, tableView: UITableView) {
cellsData.remove(at: indexPath.row)
CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock {
tableView.reloadData()
}
tableView.deleteRows(at: [indexPath], with: .left)
tableView.endUpdates()
CATransaction.commit()
}
tableView.reloadData() do the thing that fixing appearing cell above the headerView, but kills animation. So if you don't care about animation you can add only reloadData().

Related

How to fix voiceover after deleting a row in a TableView

I've got some problems fixing voiceover after deleting a row. the structure is like this:
I've got a tableview with 2 sections.
The first section got a header of height = 0 and only one row of variable height.
The second section got a header with fixed height with a button inside; rows in this sections can be 'n'.
When the user tap the button inside the header the cell in the first section is deleted or re-inserted according to the previous state.
In the normal 'state' with the cell expanded the voiceover works perfectly. When the user taps the button and delete the row in the first section the voiceover breaks. If I browse from top to bottom it's all ok. Instead when you scroll upwards the vo reads the cells visible on the screen but reads the header of the first section before the cells below it.
Insert and deleting is pretty simple:
let indexPath = IndexPath(row: 0, section: 0)
if isExpanded {
if tableView.contentOffset.y <= 0 {
tableView.insertRows(at: [indexPath], with: .automatic)
} else {
tableView.reloadData()
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
} else {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
cells in each sections have: isAccessibilityElement = false
the accessibility element is the card inside the cell like this:
cardView.isAccessibilityElement = true
cardView.accessibilityTraits = .button
I would really appreciate your help, I have tried different solutions but none of them work. It's pretty much a headache!
Let me know if you need more info to solve this.
Thank you.
Solved this by keeping always a row in the first section.
tableView.performBatchUpdates({
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.insertRows(at: [indexPath], with: .fade)
}, completion: nil)
But when the variable isExpanded is false the height of the rows in first section is set to 0 instead of automatic.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return isExpanded ? UITableView.automaticDimension : 0
}
return UITableView.automaticDimension
}

iOS UITableView deleted cell contents re appear when inserting new cell

I've a table view where cells can be inserted and deleted. For insertion of cells, I use the following code:
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: cellCount-2, section: 0)], with: .automatic)
tableView.endUpdates()
For deleting cells, I use the following code:
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
Attaching the gif of the issue I face. On deleting a cell and inserting a new one, the contents of the cell gets populated in the new cell. Can someone help me sort this issue?
If you are using the standard UITableViewCell remember to reset the content inside the UITableViewDelegate function cellForRowAtIndexPath since the dequeueReusableCell will recycle an already initialized cell (that has to be brought to its original state)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "aCellIdentifier", for: indexPath)!
...
cell.title.text = ""
cell.description.text = ""
}
A typical approach is however to subclass UITableViewCell and implement prepareForReuse method (which is called automatically before the cell being reused), where you will eventually reset all labels, images, subviews to the initial state
override func prepareForReuse() {
super.prepareForReuse()
self.labelScore.text = ""
self.labelDate.text = ""
}

how to update a uitableview cell without reloadRows and reloadData swift

I need to update tableview cell without reloadRows and reloadData method in swift. Is It possible?
You can use tableview.indexPathsForVisibleRows if you wanna just update the ones on the screen and the others will be updated through cellForRow / willDisplayCell
Then you would traditionally do something like
tableview.indexPathsForVisibleRows.forEach {
if let cell = tableview.cellForRow(at: $0) as? MyCell {
cell.configure()
}
}
Try this piece of code:
UIView.setAnimationsEnabled(false)
self.yourTableView.beginUpdates()
self.yourTableView.reloadSections(NSIndexSet(index:indexToBeReload) as IndexSet, with: UITableViewRowAnimation.none)
self.yourTableView.endUpdates()
If You want to update cell content size, You should use beginUpdates() and endUpdates() to change content size of UITableViewCell, in this case heightForRowAtindexPath will called for each cell in tableView and update height of TableviewCell. for iOS > 10, You should prefer performBatchUpdates(_:completion:) instead of beginUpdates() and endUpdates().
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
For more information
https://appengineer.in/2018/07/11/resize-uitableviewcell-size-without-fluctuation-and-jerk/
https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates

Tableview is bouncing when reloadRows(at: [indexPath], with: .fade) is called from did select row at index path

I am having this weird issue. when I scroll tableview and update some cell it bounce equivalent to the amount first cell scrolled.
I am having one view controller with tableview in it and based on user select some rows i'm updating only that row using below code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let index = indexPath.row
print(index)
let service = services[indexPath.row]
if service.isEnabled {
service.isEnabled = false
}
else {
service.isEnabled = true
}
let indexPath = IndexPath(item: index, section: 0)
serviceTableView.reloadRows(at: [indexPath], with: .fade)
}
this is working fine if I don't scroll the table view but if i scroll table view and select some cell its bounce the entire tableview
Things already tried
Removing all constraints of table view, it still bounce
Removing all config methods from cellForRowAt indexPath
Different simulators
also I am not doing anything in section view.
PS: What I observe is that it only happens when first cell is partially visible/hidden.

UITableView jumps after calling reloadSections:withRowAnimation: [duplicate]

This question already has answers here:
reloadData() of UITableView with Dynamic cell heights causes jumpy scrolling
(22 answers)
Closed 4 years ago.
I need to expand/collapse a section of UITableView. I do this by calling reloadSections:withRowAnimation: and returning 0 from tableView:numberOfRowsInSection: if the section is supposed to be collapsed.
It works fine except for one case. If the table view is scrolled all the way down and content size decreases after collapse, it ends up being scrolled beyond maximum offset.
Now instead of scrolling in place with animation it just snaps there, which looks ugly:
Here's what I have tried:
Wrapping reloadSections:withRowAnimation: in beginUpdates/endUpdates:
tableView.beginUpdates()
tableView.reloadSections(indexSet, withRowAnimation: .Automatic)
tableView.endUpdates()
That did not help.
Wrapping reloadSections:withRowAnimation: in CATransaction with completion block, calculating the scroll distance within it and scrolling table view with animation:
CATransaction.begin()
CATransaction.setCompletionBlock {
// tableView.contentSize is incorrect at this point
let newContentOffset = ... // calculated value is not correct
tableView.setContentOffset(newContentOffset, animated: true)
}
tableView.beginUpdates()
tableView.reloadSections(indexSet, withRowAnimation: .Automatic)
tableView.endUpdates()
CATransaction.commit()
How do I make sure the table view does not jump?
I ran into this issue when using custom headers in collapsible sections. I did solve it by implementing.
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat

Resources