如何修复TableView中的跳跃单元格?

时间:2018-07-26 08:46:08

标签: ios swift

有一个我无法解决的问题,即-我要为向表中添加新单元格(tableView.insertRows)的平滑动画进行战斗。下面的视频显示了在开始时所有单元格是如何疯狂抽动的,我对代码进行了编码:

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)
        }
    }
}

VIDEO

2 个答案:

答案 0 :(得分:1)

通常,UITableView在无法轻松估计单元格的正确高度时开始跳跃。

要解决此问题,请先通过tableView(_, estimatedHeightForRowAt: ) -> CGFloat方法返回正确的高度

第二点,您可以存储当前的contentOffset

self.tableView.beginUpdates()
let contentOffset = self.tableView.contentOffset
self.tableView.insertRows(at: [indexPath], with: .automatic)
self.tableView.contentOffset = contentOffset
self.tableView.endUpdates()

更新

因此,如果需要插入和删除几个索引,则需要在单个beginUpdates()endUpdates()块中执行此操作

尝试将您的代码更改为此:

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()
}

答案 1 :(得分:1)

如果您对表视图内容进行了多个动画更改,则应将它们全部包装到tableView.beginUpdates() ... tableView.endUpdates()个调用中。 您正在for...in循环中进行多次插入或删除。 将您的代码更改为此:

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()
    }
}

一种更好的方法是累积IndexPath您要更改为数组并立即执行所有插入或删除操作:

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)
    }
}