UITableView动画Bug - 在动画之前计算的可见区域

时间:2018-06-04 08:54:20

标签: ios uitableview animation autolayout

我有一个简单的用户界面(非常类似于Uber),用户可以在主要内容的顶部滚动表格视图。

UI和相应的UITableView动画错误可以显示为:

enter image description here

以下是发生的事情:

  • 用户点击表格视图,展开表格视图。这是通过添加确保tableView.top = topMenu.bottom的布局约束来完成的。被删除的约束是tableView.height = 30。一切都很好。
  • 用户然后向下滚动一定量(55+像素),约束将恢复为原始状态。这发生在动画块内,因此流程看起来很流畅。
  • 这里发生了错误。据我所知,tableView的可见区域计算了动画结束后的样子。但是,此计算在动画之前发生。因此,在动画期间,表格视图上只显示1-2个单元格;造成这个错误。
  • 我可以通过暂时将tableView的高度设置为一个较大的值并在动画结束后将其设置回一个较小的值来解决此问题。但是,这不起作用,因为iPhoneView上的安全区域被tableView覆盖。

相关代码在这里:

    private func animateTheChange() {
        UIView.animate(withDuration: 0.8, animations: {
            self.view.setNeedsUpdateConstraints()
            self.view.layoutIfNeeded()
        })
    }

    override func updateViewConstraints() {
        self.touchConstraints()
        super.updateViewConstraints()
    }

    private func touchConstraints() {
        if self.collapsed {
            self.view.addConstraint(self.collapsedConstraint)
            self.view.removeConstraint(self.expandedConstraint)
            if UserHardware.IS_IPHONE_X {
                self.bottomConstraint.constant = 0
            }
        }
        else { //  Expand
            self.view.addConstraint(self.expandedConstraint)
            self.view.removeConstraint(self.collapsedConstraint)
            if UserHardware.IS_IPHONE_X {
                self.bottomConstraint.constant = 34
            }
        }
    }

相关的Stackoverflow问题(有帮助但无法解决问题):

1 个答案:

答案 0 :(得分:1)

一种选择......

  • 将tableView嵌入“包含”UIView
  • 将tableView约束到包含视图的顶部和底部
  • 将包含视图底部限制在安全区域底部
  • 使用topMenu(默认为低)将包含视图顶部限制在Priority of 250的底部,并将其连接到@IBOutlet var tableContainerTop: NSLayoutConstraint!
  • 使用30(默认为高)将包含视图的高度限制为Priority of 750,并将其连接到@IBOutlet var tableContainerHeight: NSLayoutConstraint!

如果要“扩展”或“折叠”tableView,请更改包含视图约束的优先级。

    UIView.animate(withDuration: 0.8, animations: {

        if self.isExpanded {
            self.tableContainerHeight.priority = .defaultHigh
            self.tableContainerTop.priority = .defaultLow
        } else {
            self.tableContainerHeight.priority = .defaultLow
            self.tableContainerTop.priority = .defaultHigh
        }
        self.view.layoutIfNeeded()

    })