同时处理两个手势识别器

Handle two Gesture Recognizer simultaneously

问题很简单:我有一个 ViewController 上面有一个 GestureRecognizer:

    panGR = UIPanGestureRecognizer(target: self,
              action: #selector(handlePan(gestureRecognizer:)))
    view.addGestureRecognizer(panGR)

在这个 ViewController 中,我还有一个 class WhishlistTableViewController: UITableViewController,上面有“滑动删除”功能:

override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let deleteAction = UIContextualAction(style: .destructive, title: "Löschen") {[weak self] _, _, completionHandler in
        self!.deleteWishDelegate?.deleteWish(indexPath)
    completionHandler(true)
    }
    deleteAction.backgroundColor = .red
    deleteAction.image = UIImage(systemName: "trash")
    let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
    configuration.performsFirstActionWithFullSwipe = false
    return configuration
}

这是我的 panGR 的视频:Screenvideo

这是我的 handlePan 函数:

// handle swqipe down gesture
@objc private func handlePan(gestureRecognizer:UIPanGestureRecognizer) {
    // calculate the progress based on how far the user moved
    let translation = panGR.translation(in: nil)
    let progress = translation.y / 2 / view.bounds.height

  switch panGR.state {
  case .began:
    // begin the transition as normal
    self.dismissView()
    break
  case .changed:

    Hero.shared.update(progress)

  default:
    // finish or cancel the transition based on the progress and user's touch velocity
       if progress + panGR.velocity(in: nil).y / view.bounds.height > 0.3 {
        self.dismissView()
         Hero.shared.finish()
       } else {
         Hero.shared.cancel()
       }
  }
}

问题是这两者发生了冲突。 “滑动删除”只有在我禁用另一个 GestureRecognizer 时才有效。为什么会这样,我该如何解决?

你应该试试这个。

class YourViewController: UIViewController, UIGestureRecognizerDelegate

在 viewDidLoad 中

yourGesture.delegate = self

最后

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

    // If you wish to do conditionally.
    /*if (gestureRecognizer is UIPanGestureRecognizer || gestureRecognizer is UIRotationGestureRecognizer) {
        return true
    } else {
        return false
    }*/
}

当您在视图顶部做平移手势时,将调用手势平移识别器。如果 tableview 是视图的一部分,当您尝试执行滑动删除功能时,手势 handlePan 将被调用。

如果您想要 2 个单独的行为,则将您希望手势 handlePan 在其中执行的视图部分与您希望滑动删除功能在其中执行的表视图分开。

如下所示:

   panGR = UIPanGestureRecognizer(target: self,
          action: #selector(handlePan(gestureRecognizer:)))
   gestureView.addGestureRecognizer(panGR)
   view.addSubView(gestureView)

编辑:您还可以获得按下位置的 location/co-ordinates,并且可以计算要忽略的区域。

    currentLocation = gesture.location(in: self.view)
      

通常这很简单,

首先,您不需要向视图添加手势识别器,

我们已经有了“touchesBegan”函数,它告诉这个对象一个或多个新的触摸发生在视图中或 window。

所以在您的代码中,您只需要使用它而不是手势识别器,它就会起作用。

class ViewController: UIViewController,UITableViewDataSource {
  
    
    let tableView:UITableView = {
     let table =  UITableView()
        table.backgroundColor = .blue
        table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        return table
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
    //    tableView.delegate = self
        tableView.dataSource = self
        view.addSubview(tableView)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        tableView.frame = CGRect(x: 0, y: view.frame.height/2, width: view.frame.width, height:view.frame.height/2 )
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
          return 20
      }
      
      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
          cell.backgroundColor = .blue
          return cell
      }
      

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }// we store the touch
        
        let location = touch.location(in: view)//we retrieve the location of the touch
        
        if view.bounds.contains(location){//we check if our touch is inside our view
            
            // if our touch is inside  the view ,do the action you wanted to do with your gesture recognizer
            print("inside the view, outside tableView(Controller)")
        }else{
            // else here means here that  this is not inside the view, so it is inside  the tableView(Controller)
            // if this is not inside the view, you can select tableView,rows,swipe-to-delete etc, basically do whatever action you want with it
        }
    }
   
    
  
}



在 Mitesh Mistri 的帮助下,我让它运行起来了。缺少的另一件事是禁用 tableView 内的 panGR 的功能,否则用户将无法滚动。这是使它起作用的两个函数:

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

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if self.theTableView.view.bounds.contains(touch.location(in: self.theTableView.view)) {
        return false
    }
    return true
}