UITableView单元格折叠动画看起来很糟糕

问题描述 投票:2回答:4

我有一个问题,使细胞崩溃动画看起来始终如一。

我的形象胜过千言万语。这是同一个表视图的两个GIF:

Great Terrible

折叠对于单元格“6”非常有效,但对于“5”则不然。看起来整个UITableView内容在执行折叠动画之前会跳起来。

我没有使用UITableViewAutomaticDimension用于UITableView的rowHeight。相反,我通过tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath)方法提供行高,并使用表格视图的beginUpdates / endUpdates扩展/折叠单元格。正如您所看到的,我也使用tableView.scrollToRow(at: indexPath, at: .none, animated: true)滚动到扩展行(但只有在扩展时,所以它可能无关紧要)。

UITableViewController的子类嵌入在具有大标题和搜索栏的UINavigationController中(此处不可见,因为内容向下滚动)。 UINavigationController嵌入在UITabBarController中。

这是相关的扩展/折叠部分。传递nil indexPath参数时,已经展开的单元格将会崩溃。

func expandRow(at indexPath: IndexPath?) {
    selectedIndexPath = indexPath
    tableView.beginUpdates()
    tableView.endUpdates()

    if let ip = indexPath {
        tableView.scrollToRow(at: ip, at: .none, animated: true)
    }
}

此方法计算行高,并由tableView(_:heightForRowAt:)tableView(_:estimatedHeightForRowAt:)调用:

private func heightForRow(at indexPath: IndexPath) -> CGFloat {
    var height: CGFloat
    if selectedIndexPath == indexPath {
        // Add some height variety
        height = 300 + CGFloat((indexPath.row % 4) * 20)
    } else {
        height = 70
    }
    return height
}

这是GitHub回购:https://github.com/AleksanderMaj/CellCollapse

知道怎么改进吗?

此问题是维度敏感的(在具有不同屏幕大小的设备上执行相同步骤后,此问题可能无法重现)。这是在带有iOS 11.3的iPhone 7模拟器上录制的。


编辑1:保持自动滚动到扩展单元格非常重要。

ios swift uitableview ios11
4个回答
3
投票

通过扩展方法的微小改动,我能够顺利完成:

func expandRow(at indexPath: IndexPath?) {
    selectedIndexPath = indexPath
    tableView.beginUpdates()
    tableView.endUpdates()

    if let ip = indexPath {
        tableView.scrollToRow(at: ip, at: .middle, animated: true)
    }
}

Before After


1
投票

您正在滚动到扩展行,这使得UITableView跳跃了一点。

所以这是一个重构的expandRow(at:)方法:

func expandRow(at indexPath: IndexPath?) {
    self.contentOffset = self.tableView.contentOffset
    selectedIndexPath = indexPath
    tableView.beginUpdates()
    tableView.endUpdates()

    if let contentOffset = self.contentOffset {
        tableView.contentOffset = contentOffset
    }
}

您还需要将var contentOffset: CGPoint?属性添加到控制器。

更新我错了,你不需要把selectedIndexPath = indexPath btw beginUpdates()endUpdates()方法。更新了代码示例


1
投票

如果在每行调整行高时调整此问题,请单击。与@Taras的答案几乎相同,虽然在这里,需要先删除动画,然后再分配保存的contentOffset。希望这可以帮助 :)

func expandRow() {
    let savedContentOffset = tableView.contentOffset

    tableView.beginUpdates()
    tableView.endUpdates()
    tableView.layer.removeAllAnimations()

    tableView.setContentOffset(savedContentOffset, animated: false)
}

0
投票

我有个主意。我不确定这个诀窍是否正常。

可折叠表具有以下功能:表格视图的高度在展开或折叠时会发生变化。

如果我们使用从UITableView继承的自定义视图,我们可以覆盖视图,contentSize和contentOffset的属性。通过覆盖这两个属性,我们可以使表视图停止,禁用滚动一段时间。

var contentSizeChanging: Bool = false

override var contentSize: CGSize {
    willSet {
        contentSizeChanging = true
    }
    didSet {
        contentSizeChanging = false
    }
}

override var contentOffset: CGPoint {
    get {
        return super.contentOffset
    }
    set(newValue) {
        if contentSizeChanging { return }
        super.contentOffset = newValue
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.