【问题标题】:UIPanGestureRecognizer on tableView does not scroll table itemstableView 上的 UIPanGestureRecognizer 不滚动表项
【发布时间】:2018-05-31 07:24:02
【问题描述】:

UITableView (Swift 4.0) 上使用 UIPanGesture 来拖动 tableview 位置(即原点)。 UIPanGestureRecognizer 检测触摸事件并使用它们。在某些时候,我想将事件委托给表,以便它滚动其项目。我该怎么做?

我尝试了什么:

@objc func tableViewDragged(gestureRecognizer: UIPanGestureRecognizer) {

        if gestureRecognizer.state == UIGestureRecognizerState.began || gestureRecognizer.state == UIGestureRecognizerState.changed {

            let translation = gestureRecognizer.translation(in: self.view)

// if origin moved to map origin it should not scroll above but cell should scroll normally. But returning does not help scrolling cells
            if self.tableView.frame.origin == self.mapContainer.frame.origin && translation.y < 0 {

                return
            }

            var frame = self.tableView.frame
            let nHeight = (frame.origin.y + translation.y)

            if (nHeight < self.view.frame.size.height) {

                frame.origin.y = nHeight
                self.tableView.frame = frame
                gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
            }
        }
}

手势添加到 tableView

let gesture = UIPanGestureRecognizer(target: self, action: #selector(self.tableViewDragged(gestureRecognizer:)))
self.tableView.addGestureRecognizer(gesture)
self.tableView.isUserInteractionEnabled = true
gesture.delegate = self

问题总结:

对于在 tableview 的任何点(即在任何单元格上)的相同平移手势,当 tableviews 原点固定在容器的左上角时,我需要滚动项目。否则我必须移动 tableview 直到它连接到左上角。此外,如果没有东西可以向下滚动,我需要再次移动下面的表格以进行平移手势。

*问题用例:*

  1. 初始条件 - tableview 原点位于屏幕中间, 即(0,高度/2)
  2. 向上平移手势 - 表格垂直向上移动,但没有项目滚动,直到原点卡在 (0,0) 上
  3. 向上平移手势 - 单元格项目向上移动,但表格本身不向上移动
  4. 向上平移手势 - 单元格项目向上移动直到单元格末尾
  5. 向下平移手势 - 单元格项目向下移动直到索引 0,假设来到 0 索引
  6. 向下平移手势 - 表格视图垂直向下移动,直到其原点到达屏幕中间(0,高度/2)

【问题讨论】:

  • 请发布您的代码或尝试
  • @SPatel 请查看更新后的帖子

标签: ios swift uigesturerecognizer uipangesturerecognizer


【解决方案1】:

使用tableView自己的panGestureRecognizer(不添加新的gestureRecognizer)的最佳方法,例如:

tableView.panGestureRecognizer.addTarget(self, action: #selector(self.tableViewDragged(gestureRecognizer:))

动作

@objc func tableViewDragged(gestureRecognizer: UIPanGestureRecognizer) {
    guard tableView.contentOffset.y < 0 else { return }
    if gestureRecognizer.state == UIGestureRecognizerState.began || gestureRecognizer.state == UIGestureRecognizerState.changed {

    let translation = gestureRecognizer.translation(in: self.view)

    // if origin moved to map origin it should not scroll above but cell should scroll normally. But returning does not help scrolling cells
    if self.tableView.frame.origin == self.mapContainer.frame.origin && translation.y < 0 {

        return
    }

    var frame = self.tableView.frame
    let nHeight = (frame.origin.y + translation.y)

    if (nHeight < self.view.frame.size.height) {

        frame.origin.y = nHeight
        self.tableView.frame = frame
        gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
    }
}
}

【讨论】:

  • tableView.panGestureRecognizer.delegate = self 使应用程序崩溃
  • 为什么分配委托。删除这一行只需在视图中添加可能的代码并加载
  • 控制什么时候滚动,什么时候不滚动。请参考我的实际问题。有两种情况(应将平移手势应用于 tableview 以移动其位置,应将平移手势应用于滚动其项目)。如何控制这种行为?
  • @SazzadHissainKhan 因为您需要在“tableViewDragged”方法中检查 tableview 的 contentOffset。如何控制?参考这个答案-> stackoverflow.com/a/48661043/6630644
  • 没有解决问题。对于在 tableview 的任何点(即在任何单元格上)的相同平移手势,当 tableviews 原点固定在容器的左上角时,我需要滚动项目。否则我必须移动 tableview 直到它连接到左上角。此外,如果没有东西可以向下滚动,我需要再次移动下表以进行向下手势。
【解决方案2】:

如果我理解正确,那么您想在想要滚动时取消 PanGesture。

试试这个:

func isItemAvailabe(gesture: UISwipeGestureRecognizer) -> Bool {
    if gesture.direction == .down {
        // check if we have some values in down if yes return true else false
    } else if gesture.direction == .up {
        // check if we have some values in up if yes return true else false
    }
    return false
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                       shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer == self.panGesture && otherGestureRecognizer == self.scrollGesture && isItemAvailabe(gesture: otherGestureRecognizer) {
        return true
    }
    return false
}

如果这能解决您的问题,或者我没有正确理解,请告诉我。

还记得添加这个:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

您可以查看更多here

【讨论】:

  • 我没有两个手势,我需要使用 tableViews 滚动手势和附加在同一个 tableview 上的另一个平移手势。我怎样才能获得 tableviews scrollGestureRecognizer?
  • @SazzadHissainKhan 检查这个答案,它将帮助您获得 tableView 的手势stackoverflow.com/a/9538266/5622566
  • 在这里你需要检查它是否是滑动(左/右)手势,然后你可以做剩下的事情。我认为在 tableView 初始化之后,您可以获得所需的手势并使用它:)
  • 没有解决问题。对于 tableview 的任何点(即在任何单元格上)的相同平移手势,当 tableviews 原点固定在容器的左上角时,我需要滚动项目。否则我必须移动 tableview 直到它连接到左上角。此外,如果没有东西可以向下滚动,我需要再次移动下面的表格以进行平移手势。
  • 为此,您可以尝试类似 hack,首先检查您的 scrollDirection 中是否还有更多项目,所以说 Pan 等待(返回 true),否则为 false
【解决方案3】:

我不知道比将您的 tableView 子类化并在其 layoutSubviews 中阻止其 contentOffset 更好的解决方案。类似的东西:

class MyTableView: UITableView {
    var blocksOffsetAtZero = false
    override func layoutSubviews() {
        super.layoutSubviews()
        guard blocksOffsetAtZero else { return }
        contentOffset = .zero
    }
}

我认为这是地图应用程序中使用的解决方案。当用户在主屏幕上拖动 tableView 时,它不会滚动而是抬起,直到到达屏幕顶部,然后再次滚动。

为此,您向 tableview 添加一个手势,该手势与 tableView 的识别器同时识别并在每次识别器移动 tableView 的框架时阻止 tableView 的contentOffset

更新 https://github.com/gaetanzanella/mapLike

您是否正确实现了委托?

// MARK: - UIGestureRecognizerDelegate

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                       shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

试试类似的东西:

@objc func tableViewDragged(gestureRecognizer: UIPanGestureRecognizer) {

    if gestureRecognizer.state == UIGestureRecognizerState.began || gestureRecognizer.state == UIGestureRecognizerState.changed {

        let translation = gestureRecognizer.translation(in: self.view)

        var frame = self.tableView.frame
        let nHeight = (frame.origin.y + translation.y)

        if (nHeight < self.view.frame.size.height) {
            frame.origin.y = nHeight
            self.tableView.frame = frame
            gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
            tableView.blocksOffsetAtZero = true
        } else {
            tableView.blocksOffsetAtZero = false
        }
    }
}

主要思想:当你改变框架时,阻止滚动。

您也可以使用 kamaldeep singh bhatia 提出的委托技术,但您将无法移动第一个 tableView 然后以单个手势滚动。

看一个例子here

【讨论】:

  • 它会阻止手势事件但它会委托事件来滚动项目吗?
  • 它会阻止滚动,而不是手势。它将覆盖更新 tableView 的 contentOffset 并调用setNeedsLayout() 的内部手势识别器的行为。也许您可以添加代码或更多关于您正在尝试做的事情的解释。
  • 由于遗留的复杂性,我被要求不要创建任何 tableview 子类。是否可以使用 UITableView 实现类似的行为?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-31
  • 2019-05-16
  • 2013-01-17
  • 2018-12-17
相关资源
最近更新 更多