首页 > 解决方案 > 自定尺寸单元格高度变化导致跳跃动画

问题描述

我已经使用 Autolayout 设置了一个带有动态高度单元格的表格视图,即 UITableView.automaticDimension。这工作正常。现在我想要实现的是改变单元格的高度并为其设置动画。问题是当我更改单元格高度并为其设置动画时,动画会奇怪地跳跃。仅当我向下滚动一点然后展开/折叠单元格时才会发生跳转。我有一个简单的表格视图单元格。它有一个标签和一个具有固定高度约束的空 UIView。当我想折叠/展开单元格时,我只需将该高度约束的常数更改为 0 或 300。

我在互联网上尝试了许多可折叠的 tableview 示例。他们都有这个问题。一个例外是https://github.com/Ramotion/folding-cell,但它使用固定高度的单元格。

我已经尝试了很多选项来为单元格高度变化设置动画。

1-> 在 didSelectRow 上,我更改了高度约束并调用 tableview beginUpdate 和 endUpdates。不能解决跳跃问题。

2-> 更改我的模型并调用 tableView.reloadRows。不能解决跳跃问题。

这是我的表格视图单元设置的屏幕截图。 https://drive.google.com/open?id=12nba6cwRszxRlaSA-IhrX3X_vLZ4AWxy

此问题的视频链接: https ://drive.google.com/open?id=19Xmc0PMXT0EuHTJeeGHm4M5aPoChAtf3

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        tableView.delegate = self
        tableView.estimatedRowHeight = 50
        tableView.rowHeight = UITableView.automaticDimension
        tableView.estimatedSectionHeaderHeight = 0
        tableView.estimatedSectionFooterHeight = 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! OuterTableViewCell
        let height: CGFloat = isCellExpanded[indexPath.row] ? 300 : 0

        cell.labelText.text = "Cell Number: \(indexPath.row + 1)"
        cell.buttonExpansionToggle.setImage(UIImage(named: isCellExpanded[indexPath.row] ? "arrow-down" : "arrow-right"),
                                            for: .normal)
        cell.viewContainerHeight.constant = height
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        isCellExpanded[indexPath.row] = !isCellExpanded[indexPath.row]
        tableView.reloadRows(at: [indexPath], with: .automatic)
    }

didSelectRow 的另一种形式:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        guard let cell = tableView.cellForRow(at: indexPath) as? OuterTableViewCell else { return }
        isCellExpanded[indexPath.row] = !isCellExpanded[indexPath.row]
        let height: CGFloat = self.isCellExpanded[indexPath.row] ? 300 : 0
        cell.viewContainerHeight.constant = height
        cell.layoutIfNeeded()
        UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {


            tableView.beginUpdates()
            tableView.endUpdates()

            // fix https://github.com/Ramotion/folding-cell/issues/169
            if cell.frame.maxY > tableView.frame.maxY {
                tableView.scrollToRow(at: indexPath, at: UITableView.ScrollPosition.bottom, animated: true)
            }
        }, completion: nil)
    }

我还尝试在动画块之外调用 beginUpdates() 和 endUpdates(),但问题仍然存在。

我希望动画流畅。希望有人可以提供帮助。如果有人可以在 github 上设置一个简单的演示项目,那就太棒了。

演示项目链接:https ://gitlab.com/FahadMasoodP/nested-tableviews

任何形式的帮助表示赞赏。谢谢。

标签: iosswiftuitableview

解决方案


我的解决方案是添加动态估计行高。我认为这是 UIKit 的错误。不会出现 iOS 13 问题。

首先,您需要添加属性estimateRowHeightStorage以通过 indexpath 存储估计高度

var estimateRowHeightStorage: [IndexPath:CGFloat] = [:]

其次,您需要存储单元格的当前高度以供以后使用

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    estimateRowHeightStorage[indexPath] = cell.frame.size.height
}

FinalestimateRowHeightStorage用于设置估计行高。

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    if estimateRowHeightStorage[indexPath] != nil {
        return estimateRowHeightStorage[indexPath]!
    }

    return 50
}

跑步和感受。

我确实在您的情况下找到了新的解决方案。如果在展开时硬固定高度。只需要改变一些东西。estimatedHeightForRowAt用函数替换上面的所有代码

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    let height: CGFloat = isCellExpanded[indexPath.row] ? 373 : 73

    return height
}

推荐阅读