约束更改后 UITableView 水龙头第一次不工作

UITableView tap not working first time after constraints change

重要提示: 我的问题不是我正在实施 didDeelectRowAt 而不是 didSelectRowAt。已经检查过:)

我有一个 UITableView 显示在模态呈现的视图控制器的部分屏幕上。当用户拖动时,它会调整为全屏大小并返回到某个定义的最小高度。我通过从 UIScrollViewDelegate:

中实现以下方法来做到这一点
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    guard !scrollView.isDecelerating else { return }

    let contentOffset = scrollView.contentOffset.y
    if tableViewHeightConstraint.constant < view.frame.height && contentOffset > 0.0 {
        tableViewHeightConstraint.constant = min(contentOffset + tableViewHeightConstraint.constant, view.frame.height)
        scrollView.contentOffset.y = 0.0
        return
    }

    if tableViewHeightConstraint.constant > minViewHeight && contentOffset < 0.0 {
        tableViewHeightConstraint.constant = max(tableViewHeightConstraint.constant + contentOffset, minViewHeight)
        scrollView.contentOffset.y = 0.0
    }
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    // Here I have some calculations if depending the dragging end position and the velocity the end size should be full screen or `minViewHeight`
    // After calculating what the end size should be I'm animating the size change
    heightConstraint.constant = newConstraintHeight
    UIView.animate(withDuration: TimeInterval(calculatedAnimationDuration), delay: 0.0, options: .curveEaseOut, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)
}

关于调整大小和滚动的一切都很好,但有一个问题,我无法弄清楚为什么会这样。内容如下:

我注意到的一件事是,在将 table 视图拖回到最小高度后,滚动指示器不会隐藏。第一次点击它隐藏,第二次点击 didSelectRowAt 被调用。

更新:

这是问题的测试回购:https://github.com/nikmin/DragTest

如果拖动不完美,请不要介意,我只是放了一些东西让任何人都可以尝试,但我认为这个问题很容易重现。

还有一件事......如果你从全尺寸一直拖到底部所以 table 视图达到最小高度并且你继续拖动所以内容偏移量 < 0 然后你释放,问题没有发生。

看起来内容偏移设置不正确。第一次触摸会取消不正确的位置(取消滚动),这就是它未注册的原因。如果我们可以访问完整代码来检查它可能会更好,因为我不能告诉你问题到底出在哪里,但我想它在方法 scrollViewDidScroll.

TableView 拖到 return 到最小高度,然后点击一个单元格,没有任何反应,因为:

  • 当您拖动以将 table 视图展开为全屏时,scrollView.isDeceleratingtrue。所以 scrollViewDidScroll 方法中的代码将 运行.

  • 但是当你把TableView拖到return到最小高度时,scrollViewDidScroll就是false。所以 scrollViewDidScroll 方法中的代码不会 运行。它让第一次点击什么都不做。

只需从 scrollViewDidScroll 中删除 guard !scrollView.isDecelerating else { return }。向下拖动TableView后,您将正常点击单元格。

但是你需要稍微改变一下逻辑,去掉上面那行动画会出错

希望对您有所帮助;)

在尝试找出解决方案但没有结果后,我们(我和一名用户体验设计师)决定稍微改变一下行为。

因此,在我实现此应用程序的真实场景中,table 视图位于另一个视图内,该视图还有一个标题标签和 table 视图上方的一些其他视图。我们决定向这个根视图添加一个平移手势识别器,并在视图具有最小大小时禁用 table 视图的滚动。这样,只要用户试图拖动视图内的任何地方(包括 table 视图),平移手势识别器就会接管,因此视图的扩展有效。单元格中的水龙头仍然有效。

当视图具有最大高度时,table 视图滚动启用,以便用户可以滚动。这种方法的缺点是,当用户滚动到 table 视图的顶部并继续滚动时,视图不会减小大小。但他仍然可以选择通过拖动 table 视图上方的任何视图来将其向下拖动。这样向下拖动时,只有table视图的大小发生变化,内容偏移量没有变化,这是问题的根源(同时改变)。