Reputation: 81
There is one problem, I can not solve, namely - I fight with a smooth animation of adding new cells to the table (tableView.insertRows). The video below shows how at the opening all the cells are wildly jerking, I encode the code:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (destinationData?[indexPath.row]) != nil {
return 110
} else {
return 95
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (destinationData?[indexPath.row]) != nil {
if(indexPath.row + 1 >= (destinationData?.count)!) {
expandCell(tableView: tableView, index: indexPath.row)
}
else {
if(destinationData?[indexPath.row+1] != nil) {
expandCell(tableView: tableView, index: indexPath.row)
// Close Cell (remove ExpansionCells)
} else {
contractCell(tableView: tableView, index: indexPath.row)
}
}
}
}
private func expandCell(tableView: UITableView, index: Int) {
if let infoMain = destinationData?[index]?.infoMain {
for i in 1...infoMain.count {
destinationData?.insert(nil, at: index + 1)
tableView.insertRows(at: [IndexPath(row: index + i, section: 0)] , with: .bottom)
}
}
}
private func contractCell(tableView: UITableView, index: Int) {
if let infoMain = destinationData?[index]?.infoMain {
for _ in 1...infoMain.count {
destinationData?.remove(at: index + 1)
tableView.deleteRows(at: [IndexPath(row: index + 1, section: 0)], with: .top)
}
}
}
Upvotes: 2
Views: 586
Reputation: 2829
Usually UITableView
start jumping when it can't easily estimate correct height for cell.
To fix that, first return correct height in tableView(_, estimatedHeightForRowAt: ) -> CGFloat
method
Second point, you can store current contentOffset
self.tableView.beginUpdates()
let contentOffset = self.tableView.contentOffset
self.tableView.insertRows(at: [indexPath], with: .automatic)
self.tableView.contentOffset = contentOffset
self.tableView.endUpdates()
UPDATE
So if you are need to insert and delete couple of indexes, you need to perform this operation in single beginUpdates()endUpdates()
block
Try to change your code to this:
if let infoMain = destinationData?[index]?.infoMain {
self.tableView.beginUpdates()
let contentOffset = self.tableView.contentOffset
var indexes: [IndexPath] = []
for i in 1...infoMain.count {
destinationData?.insert(nil, at: index + 1)
indexes.append(IndexPath(row: index + i, section: 0))
}
tableView.insertRows(at: indexes, with: .bottom)
self.tableView.contentOffset = contentOffset
self.tableView.endUpdates()
}
if let infoMain = destinationData?[index]?.infoMain {
self.tableView.beginUpdates()
let contentOffset = self.tableView.contentOffset
for _ in 1...infoMain.count {
destinationData?.remove(at: index + 1)
indexes.append(IndexPath(row: index + i, section: 0))
}
tableView.deleteRows(at: indexes, with: .top)
self.tableView.contentOffset = contentOffset
self.tableView.endUpdates()
}
Upvotes: 1
Reputation: 523
If you do multiple animated changes to tableview content you should wrap them all to tableView.beginUpdates() ... tableView.endUpdates()
calls.
You are doing multiple insertion or deletion in for...in
loop.
Change your code to this:
private func expandCell(tableView: UITableView, index: Int) {
if let infoMain = destinationData?[index]?.infoMain {
tableView.beginUpdates()
for i in 1...infoMain.count {
destinationData?.insert(nil, at: index + 1)
tableView.insertRows(at: [IndexPath(row: index + i, section: 0)] , with: .bottom)
}
tableView.endUpdates()
}
}
private func contractCell(tableView: UITableView, index: Int) {
if let infoMain = destinationData?[index]?.infoMain {
tableView.beginUpdates()
for _ in 1...infoMain.count {
destinationData?.remove(at: index + 1)
tableView.deleteRows(at: [IndexPath(row: index + 1, section: 0)], with: .top)
}
tableView.endUpdates()
}
}
Even better approach is to accumulate IndexPath
's you want to change into array and perform all insertions or deletions at once:
private func expandCell(tableView: UITableView, index: Int) {
if let infoMain = destinationData?[index]?.infoMain {
var indexesToInsert = [IndexPath]()
for i in 1...infoMain.count {
destinationData?.insert(nil, at: index + 1)
indexesToInsert.append(IndexPath(row: index + i, section: 0))
}
tableView.insertRows(at: indexesToInsert, with: .bottom)
}
}
private func contractCell(tableView: UITableView, index: Int) {
if let infoMain = destinationData?[index]?.infoMain {
var indexesToDelete = [IndexPath]()
for _ in 1...infoMain.count {
destinationData?.remove(at: index + 1)
indexesToDelete.append(IndexPath(row: index + 1, section: 0))
}
tableView.deleteRows(at: indexesToDelete, with: .top)
}
}
Upvotes: 1