处理多个视图的UIPanGestureRecognizer手势(一个覆盖另一个)

时间:2015-07-10 19:21:44

标签: ios swift uitableview uigesturerecognizer uipangesturerecognizer

很抱歉这么长的问题,但觉得我应该传达我的尝试。

我在导航控制器中看到了viewA。然后我将viewB(包含UITableView)的子视图添加到viewA并偏移其原点高度,使其仅覆盖屏幕的一半(另一半从底部溢出屏幕)。我希望能够向上拖动viewB,但是当它到达导航栏的底部时它会停止,当它到达原点偏移点时向下拖动时同样会停止。这是我成功实现的。

但是,我希望UITableView互动仅在viewB处于其上方位置时启用,因此不会响应任何其他位置的手势。从本质上讲,向上拖动viewB以完全覆盖viewA应启用与UITableView的互动。

这里棘手的部分是我希望它能够做到以下几点:

  1. 如果viewB处于其上方位置以便覆盖屏幕,则UITableView内容偏移量为0(即我们位于表格的顶部)并且用户进行平移手势向下,手势不应与UITableView互动,但应向下移动viewB
  2. 上述情况下的任何其他平移手势都应该是与UITableView的交互。
  3. 如果viewB处于其上方位置以覆盖屏幕,UITableView内容偏移 NOT 为0(即我们 NOT < / strong>在表格的顶部)并且用户向下做出平移手势,手势应该与UITableView互动。
  4. 我已经非常接近实现这一点,但我无法做到这一点。

    尝试到目前为止

    我使用UIPanGestureRecognizer来处理拖动视图。我尝试将其添加到:

      最初禁用viewB用户互动的
    • UITableView。这样我就可以上下拖动viewB而不会干扰UITableView。在viewB位于其上方位置后,我启用UITableView用户互动,然后正确地允许我与UITableView进行互动,而无需移动viewB

      但是,通过启用UITableView用户互动,这意味着触摸永远不会到达UIPanGestureRecognizer,这意味着我永远无法检测到上述第(1)点所述的情景,因此无法进行重新停用UITableView用户互动,以便viewB再次移动。

      也许通过覆盖UITableView使用的手势识别方法可以这样做?如果有可能,任何人都可以指出我正确的方向吗?

    • UITableView前面添加了一个新视图。我想也许我可以在必要时将触摸手势转发到它背后的UITableView,但我仍然没有找到办法做到这一点。

      我所能做的就是禁用手势识别器,它允许我与UITableView进行交互,但后来我遇到了与上述相同的问题。我无法检测何时重新启用它。

    • UITableView内的viewB。到目前为止,这似乎是最有希望的方式。通过设置以下方法的返回值,我可以启用和禁用对viewBUITableView的识别。

      func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
          if pulloverVC.view.frame.origin.y == bottomNavbarY &&
              pulloverVC.tableView?.contentOffset.y == 0 { // need to add gesture direction check to this condition
              viewBisAtTop = true
              return false // disable pullover control
          }
          return true // enable pullover control
      }
      
      func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
          if (gestureRecognizer as! UIPanGestureRecognizer).velocityInView(view).y < 0 && viewBisAtTop { // gesture direction check not wanted here
              return true // enable tableview control
          }
          viewBisAtTop = false
          return false // disable tableview control
      }
      

      当做出手势时(我已经使用print语句检查过),然后是bottom方法,首先调用top方法。通过对2种方法进行不同的真/假组合,我可以在viewBUITableView之间进行交互。

      要检测用户是否向下滑动,我在识别器上调用velocityInView()(如底部方法所示)。我打算在顶级方法if声明中进行此检查,但我认为这样可行,但是,尽管velocityInView()在底部方法中工作正常,但它不在顶部方法中(速度总是如此) 0)。

    我已经搜索过一些解决方案的SO,并找到许多关于相互覆盖的视图的手势处理的类似查询,但这些似乎都是关于一种手势类型,例如在一个视图上捏合,以及另一种类型,例如潘,另一方面。在我的情况下,手势类型对于两者都是相同的。

    也许有人有一个聪明的主意?或者这可能非常简单,我已经让这非常复杂了?的xD

1 个答案:

答案 0 :(得分:2)

管理以实现这一目标。

在我上面的问题中描述的方法中,我删除了最上面的一个(仅有一些更改):

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    if ((gestureRecognizer as! UIPanGestureRecognizer).velocityInView(view).y < 0
        || pulloverVC.tableView.contentOffset.y > 0)
        && pulloverVC.view.frame.origin.y == bottomNavbarY {
            return true // enable tableview control
    }
    return false
}

if语句检查覆盖UITableView是否位于 AND 的上方位置,用户不是向下拖动表格内容是偏移的(我们不是最重要的)。如果是这样,那么我们return true启用tableview。

调用此方法后,将调用实现处理我的平移手势的标准方法。在这里,我有一个if语句,检查与上面相反的情况,如果这是真的,它会阻止对覆盖viewB的控制移动:

func handlePanGesture(recognizer: UIPanGestureRecognizer) {

    let gestureIsDraggingFromTopToBottom = (recognizer.velocityInView(view).y > 0)

    if pulloverVC.view.frame.origin.y != bottomNavbarY || (pulloverVC.view.frame.origin.y == bottomNavbarY && gestureIsDraggingFromTopToBottom && pulloverVC.tableView.contentOffset.y == 0) {

    ...

现在,除非其父视图UITableView位于正确的位置,否则会保持viewB互动关闭,如果是,则禁用viewB的移动,以便仅与UITableView进行交互{1}}有效。

然后,当我们位于表格的顶部并向下拖动时,会重新禁用与UITableView的互动,并重新启用与其父视图viewB的互动。

一个罗嗦的帖子和答案,但如果有人能理解我在说什么,希望它会对你有帮助。