同时处理两个手势识别器
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
}
问题很简单:我有一个 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
}