How to disable CollectionView's vertical gesture recognizer? - ios

I am using LNPopupController framework for presenting View Controllers, the presented VC can be dismissed by dragging it down, however I have added a collection view in this VC and dragging finger in its area doesn't drag the VC down. I want this CollectionView to scroll horizontally, I tried subclassing UICollectionView and use the
gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
method but it doesn't make any difference.
Here is my code:
class MyCollectionView: UICollectionView, UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
in viewDidLoad()
func setupCollection() {
cellSize = CGSize(width: self.view.frame.width, height: self.view.frame.width)
collectionView.delegate = self
collectionView.dataSource = self
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
}
//collectionView.isScrollEnabled = false
collectionView.isPagingEnabled = true
collectionView.alwaysBounceVertical = false
}
when scrolling is disabled everything works perfectly, I can close the view by dragging the CollectionView's area.

First, I would implement UIGestureRecognizerDelegate in the view controller that contains the collection view:
extension MyViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
Then you also need to set this delegate to the proper gesture recognizer - in your code I do not see any such line that would assign the delegate to none of the gesture recognizers. I would assign it to the gesture recognizer that is responsible for dismissing the viewController:
self.popupContentView.popupInteractionGestureRecognizer.delegate = self
Call this line of code in viewDidLoad of the MyViewController (I use this name since you did not mention the name of your controller). Here I assume that popupContentView.popupInteractionGestureRecognizer is the pan gesture recognizer that dismisses the view controller (I checked quickly LNPopupController).

Author of LNPopupController here.
The other answer is correct. You need to implement the gesture recognizer's delegate and exclude it from interaction (or do even more complex stuff).
To do this, set the controller.popupContentView.popupInteractionGestureRecognizer.delegate property. Make sure controller is the actual controller you call presentPopupBarWithContentViewController:animated:completion: on.

Related

UIGestureRecognizer recognize order problem

I have a red view and a green view (green view is a subview of redview),and I add a gestureRecognizer to each of them.
And both grestureRecognizer's shouldRecognizeSimultaneouslyWith return YES.
But when I tap the green view , the redview's gesture delegate method shouldRecognizeSimultaneouslyWith is called first .
Because i think the hit-test view should be the green view . so the green view 's shouldRecognizeSimultaneouslyWith should be the first .
How do the iOS to decide which grestureRecognizer should be recogonized first ?
Post the code and print logs:
class GreenView: UIView,UIGestureRecognizerDelegate{
override func awakeFromNib() {
let gesture = UITapGestureRecognizer(target: self, action: #selector(greenTap))
gesture.delegate = self
self.addGestureRecognizer(gesture)
}
#objc func greenTap(){
print("greenTap")
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
print("greenTap shouldRecognizeSimultaneouslyWith")
return true
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
print("green gestureRecognizerShouldBegin")
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
}
class RedView: UIView,UIGestureRecognizerDelegate{
override func awakeFromNib() {
let gesture = UITapGestureRecognizer(target: self, action: #selector(redTap))
gesture.delegate = self
self.addGestureRecognizer(gesture)
}
#objc func redTap(){
print("redTap")
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
print("redTap gestureRecognizerShouldBegin")
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
print("redTap shouldRecognizeSimultaneouslyWith")
return true
}
}
and the prints are :
green gestureRecognizerShouldBegin
redTap gestureRecognizerShouldBegin
green gestureRecognizerShouldBegin
redTap shouldRecognizeSimultaneouslyWith
greenTap shouldRecognizeSimultaneouslyWith
redTap
greenTap
and we can see that the redview(superview) 's shouldRecognizeSimultaneouslyWith and action method is called before the greenview(subview)'s methods
Don't add the green view as subview of red view. Just add the green view outside red view above it and center the constraints to red view

CollectionView Cells Need Two Taps Because of GestureRecognizer

I have added GestureRecognizer for hide keyboard when user click to anywhere in view without textview. Its working well but CollectionView Cells need two tap for work, when I delete GestureRecognizer its working well but I need both of them. I have searched this in couple hours and tried so many solutions but anything is not worked.
GestureRecognizer for hide keyboard when user click to anywhere in view without textview;
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tapRecognizer.cancelsTouchesInView = false
view.addGestureRecognizer(tapRecognizer)
#objc func handleTap() {
textBody.endEditing(true)
}
You can try this method:
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true) // or textBody.endEditing(true)
}
To recognize both gestures simultaneously use below code by removing cancelsTouchesInView line. You may need to add another tap gesture for your collectionView according to your need. Or use scrollViewDidScroll event of collectionView to hide the keyboard.
//tapRecognizer.cancelsTouchesInView = false
tapRecognizer.delegate = self
view.addGestureRecognizer(tapRecognizer)
extension MyViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}

didSelectItemAt not called when using UIPanGestureRecognizer in View

I am using both a tap and pan gesture in my View. The view has a UICollectionView where I am trying to call didSelectItemAthowever the method is not called.
I have tried the following, but with no luck.
override func viewDidLoad() {
panGesture.delegate = self
tapGesture.delegate = self
}
extension AddNotebookViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
Does anybody have any idea what the issue may be ?
The problem, as you've already guessed, is that the background view's gesture recognizer swallows the tap that would select the collection view cell. To solve the problem, implement this gesture recognizer delegate method in your view controller:
func gestureRecognizerShouldBegin(_ gr: UIGestureRecognizer) -> Bool {
let p = gr.location(in: self.view)
let v = self.view.hitTest(p, with: nil)
return v == gr.view
}
The result is that if the gesture is in the collection view, the background view's gesture recognizer won't begin and normal selection will be able to take place.

How to implement a Longpress Gesture on a UITextView

Is it possible to implement a long press gesture on a UITextView? Basically, if the user tap once on a textview I want him/her to be able to edit the text. However, if he/she tap and hold on the textview (let's say for two seconds) an action will be performed? If the answer is yes please give me direction on how this could be achieved?
Follows is the solution for my problem as per kchromik's asnwer:
(1) First step is define the following extension before the ViewController Class begins:
extension ViewController: UIGestureRecognizerDelegate { func gestureRecognizer (_ gestureRecognizer: UIGestureRecognizer, shouldRecognizerSimultaneouslyWithotherGestureRecognizer: UIGestureRecognizer) -> Bool { return true}}
(2) Second step is to link the UITextView Outlet from the Main Storyboard to the swift code file:
#IBOutlet weak var testTextView: UITextView!
(3) Third step is to drag and drop a GestureRecognizer from the Object Library on top of the UITextView you want to implement a Longpress Gesture Recognizer on.
(4) The Fourth step is add the below code under viewDidLoad () {
let uilpgr = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.longpress(gestureRecognizer:)))
uilpgr.minimumPressDuration = 2
testTextView.addGestureRecognizer(uilpgr)
uiplgr.delegate = self
}
(5) The last step is to define the function to be used with the Longpress Gesture Recognizer defined earlier on:
func longpress(gestureRecognizer: UIGestureRecognizer) {
print("Long tap") // Execute what you want to do
}
By default a UILabel has user interactions disabled. Try testLabel.isUserInteractionEnabled = true in your viewDidLoad or enable it in the storyboard:
UPDATE
If you UIView has it's own gesture recogniser, you can implement following delegate:
extension ViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
And you don't forget to set uilpgr.delegate = self

Parent Controller blocking child table view UITableViewRowAction swift

I am using library call Page-Menu (https://github.com/PageMenu/PageMenu) which allow me to add child view controllers in view controller. i can scroll between this view controllers.In one of the child view controller I'm using UITableView.i am using UITableViewRowAction to delete cell but. Don't know why but table not detecting swipe gesture. if i disable Page-menu scrolling then table-view UITableViewRowAction working. i searched lots about this in google. i didn't find any solution. Thanks
Having played a bit with the library, I found the issue is to do with disabling scroll view gesture recogniser in the CAPSPageMenu view controller.
Follow these steps to enable table view editing in one of the child view controllers.
Subclass a UIScrollView like this for the PageMenu target:
class CustomScrollView : UIScrollView, UIGestureRecognizerDelegate {
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
gestureRecognizer.cancelsTouchesInView = false
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return ((self.delegate as! CAPSPageMenu).gestureDelegate?.gestureRecognizerShouldRecognizeSimultaneouslyWith(gestureRecognizer, otherGestureRecognizer: otherGestureRecognizer))!
}
}
Then in CAPSPageMenu, replace:
let controllerScrollView = UIScrollView()
with
let controllerScrollView = CustomScrollView()
Declare a protocol in the same file:
#objc public protocol CustomGestureDelegate {
func gestureRecognizerShouldRecognizeSimultaneouslyWith(_ gestureRecognizer: UIGestureRecognizer, otherGestureRecognizer: UIGestureRecognizer) -> Bool
}
And add this property to CAPSPageMenu:
open weak var gestureDelegate: CustomGestureDelegate?
Here I have made controllerArray as a property in ViewController so we can filter out the view controllers with a table view later.
var controllerArray : [UIViewController] = []
Then make ViewController conform to CustomGestureDelegate with ViewController: UIViewController, CustomGestureDelegate, and set this in viewDidLoad:
pageMenu!.gestureDelegate = self
Implement this function in ViewController (your container view controller):
func gestureRecognizerShouldRecognizeSimultaneouslyWith(_ gestureRecognizer: UIGestureRecognizer, otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if pageMenu?.currentPageIndex == 0 {
return (controllerArray[0] as! CustomGestureDelegate).gestureRecognizerShouldRecognizeSimultaneouslyWith(gestureRecognizer, otherGestureRecognizer: otherGestureRecognizer)
}
return true
}
You can add similar logic for other child view controllers with table views. Here I assumed only the initial view controller had a table view.
Make your child view controllers conform to CustomGestureDelegate by adding the following implementation:
class TestTableViewController: UITableViewController, CustomGestureDelegate {
func gestureRecognizerShouldRecognizeSimultaneouslyWith(_ gestureRecognizer: UIGestureRecognizer, otherGestureRecognizer: UIGestureRecognizer) -> Bool {
let location = gestureRecognizer.location(in: self.view)
let path = self.tableView.indexPathForRow(at: location)
if path != nil {
gestureRecognizer.isEnabled = false
}
gestureRecognizer.isEnabled = true
return true
}
}
I hope this helped you.
UPDATE:
Check out https://github.com/LemonSpike/PageMenu to see a demo of this for PageMenuDemoStoryboard target.

Resources