UICollectionView within UIScrollView: Long Press - ios

I have added a UILongPressGestureRecognizer to my UICollectionView that is within a subclass of UIScrollView. (The UIScrollView is paged so there are 3 horizontally stacked UIViewControllers).
My code to add the UILongPressGestureRecognizer:
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
longPress.delegate = self;
longPress.minimumPressDuration = 0.5;
longPress.delaysTouchesBegan = YES;
[self.collectionView addGestureRecognizer:longPress];
And an NSLog in my handleLongPress: method. Currently I hold down on a UICollectionViewCell, it highlights, but the long press is not activated. I believe my UIScrollView subclass is consuming the long press and not passing along to the UICollectionView. When I lift my finger, the didSelectItemAtIndexPath: method is called.
In my UIScrollView subclass, the only customization I have is the following:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(nonnull UIGestureRecognizer *)otherGestureRecognizer {
// This line enables the swipe to delete in the Messaging VC.
return ([otherGestureRecognizer.view.superview isKindOfClass:[UITableView class]]);
}
This was done to enable cell swiping in my UITableView, which is one of the pages of my UIScrollView. The swiping works no problem, and I have tried a number of similar checks for UICollectionView and UICollectionViewCell here but have not gotten the long press to register yet. Any advice appreciated.
Edit: I have added the long press on another UICollectionView and it is functional, but the cell never shows highlighted/selected status. I guess that is a clue as to why I can't get this long press gesture to fire.

My issue was that I was adding the gesture recognizer in the -init method. That did not work. Simply moving the code to -viewDidLoad fixed the problem.

Related

Long press and pan gesture in UICollectionView

I'm working on a custom calendar downloaded from GitHub. It's a custom view with UICollectionView added in it to show date cells. I'm adding a functionality of dragging over the cells to get multiple date values. For that I've added UILongpressgesture
What I've tried,
#property (nonatomic, strong) UILongPressGestureRecognizer *dragDateGesture;
self.dragDateGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleDragBeginDate:)];
self.dragDateGesture.delegate = self;
self.dragDateGesture.minimumPressDuration = 0.05;
[self.collectionView addGestureRecognizer:self.dragDateGesture];
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)recognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
- (void)handleDragBeginDate:(UIPanGestureRecognizer *)recognizer
{
NSLog(#"Gesture recognised");
}
In the above code, I've added long press gesture and setting simultaneous gesture recognizer to yes. I'm not sure, whether adding a long press gesture will call the handleDragBeginDate method with UIPanGestureRecognizer getter. I'm new to gesture concept. It's not calling that method while dragging over collectionview.
What might be the issue here? can anyone please guide me on this?
If the way that I'm proceeding is wrong, new suggestions will be greatly appreciated.
As far as I know, the collection view doesn't have an edit mode similar to what the table view has. Fortunately, someone has already solved this problem for you.
UICollectionView has its own panGestureRecognizer and pinchGestureRecognizer. So it's no need to add. I suggest you get touch events in its delegate functions. This is one of these:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView;

Unable to use All UITableViews after adding a subview to the UIApplication Window

Strange issue i'm running into that is honestly really frustrating. I've created a side menu bar for my app that I insert using this function:
- (void)insertMenunOnView:(UIView*)view atPosition:(CGPoint)position
{
_menuButton.frame = CGRectMake(position.x, position.y, _menuButton.frame.size.width, _menuButton.frame.size.height);
[view addSubview:_menuButton];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissMenu)];
[view addGestureRecognizer:singleTap];
view.userInteractionEnabled = true;
for (UIButton *button in _buttonList)
{
[_backgroundMenuView addSubview:button];
}
_backgroundMenuView.frame = CGRectMake(view.frame.size.width, 0, 150, view.frame.size.height);
_backgroundMenuView.backgroundColor = [UIColor colorWithRed:0.09 green:0.15 blue:0.18 alpha:0.7f];
[view addSubview:_backgroundMenuView];
}
it is implemented here in my UITableViewController viewDidAppear method:
override func viewDidAppear(animated: Bool) {
sideBar.insertMenuOnView(self.view, atPosition: CGPointMake(100, 200))
}
If I do this, it renders my TableView useless. I can select the cells if I tap rapidly back and forth between multiple cells. After about ten seconds of doing this, the cell being tapped will initiate the appropriate segue.
No I tried this hoping I'd be able to get over this problem by changing the function to
- (void)insertMenunOnView:(UIWindow*)view atPosition:(CGPoint)position
{ //// do stuff
}
Guess what!? Now every single tableView in my entire app is behaving the same as the first! Takes about thirty to forty taps until the cell finally calls didSelectRowAtIndexPath
What on earth is going on?
Disable tap gesture on view when side menu is closed and enable it when side menu is open.
At present your tap gesture is overriding tap gesture of table view.
The issue is-
When you call sideBar.insertMenuOnView(self.view, atPosition: CGPointMake(100, 200))
this method is called
- (void)insertMenunOnView:(UIView*)view atPosition:(CGPoint)position
inside your dismissMenu event handler you should remove gesture recognizer
inside above method you are adding a gesture recognizer on the current view, when you are done with this view, then you are dismissing it, but the tap gesture still exists and is added over the current view. Now when you try to select any row of the table the touch is not passed to the table as it is intercepted by the layer above it (which of-course is tap gesture recognizer added over the current view.)
To resolve this issue you should remove the tap gesture recognizer from the current view inside your dismissMenu method. Doing so will pass your touches to the corresponding row of the tableView.

How to handle a tapping on non-cell area of UITableView

I have a UITableView with a couple of UITableViewCells in it. Because I only have a couple of cells, there is an area of the table view that's not covered by the cells. And I want to do something when the empty area is tapped.
I tried adding a UITapGestureRecognizer on the table view. It detects the tapping on the empty area, but then the cells fail to respond to tapping. I tried adding the tap gesture recognizer on the super view of the table view, but the result is the same.
There must be a way to do this, but I can't quite figure it out yet. Is there any way to achieve what I want to do?
Try this:
initialize and add the UITapGestureRecognizer to your tableView:
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
gr.delaysTouchesBegan = YES;
gr.delegate = self;
[_tableView addGestureRecognizer:gr];
implement the gesture recognizer delegate method:
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
CGPoint tapPoint = [gestureRecognizer locationInView:_tableView];
UIView * clickedView = [_tableView hitTest:tapPoint withEvent:nil];
NSString *viewClassName = NSStringFromClass(clickedView.class);
return ![viewClassName hasPrefix:#"UITableViewCell"];
}
this way every tap you do outsude cells (but inside the tableview) will be recognized with your UITapGestureRecognizer
The last line: return ![viewClassName hasPrefix:#"UITableViewCell"];
should be changed to return [viewClassName hasPrefix:#"UITableView"]; since the cell you are clicking doesn't have to be a UITableViewCell, but a UIView or some other custom view

UILongPressGestureRecognizer not working on UITextField

I have a LongPress gesture recognizer initialized in the viewDidLoad method of my viewcontroller as below:
longPressGesture_= [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(displayTimeFlagCallout)];
I have a tableview in my viewcontroller. The tableview has custom cells. Each cell has 2 textfields. I want to bring up a custom popover when a user long presses on the text fields (startTime and endTime). I do not want the magnifying glass and the Copy/Paste popover to show up on long press of textfield as the standard behavior and hence before adding my gesture recognizer, I am disabling the in-built long press gesture recognizer of the text fields. I have added the following code to my cellforRowAtIndexPath method:
MyCustomCell_iPhone *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil)
{
cell = [[MyCustomCell_iPhone alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
for (UIGestureRecognizer *recognizer in cell.startTime.gestureRecognizers) {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]){
recognizer.enabled = NO;
}
}
for (UIGestureRecognizer *recognizer in cell.endTime.gestureRecognizers) {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]){
recognizer.enabled = NO;
}
}
[cell.startTime addGestureRecognizer:longPressGesture_];
[cell.endTime addGestureRecognizer:longPressGesture_];
}
However, this is not working. Nothing happens on long press now. Any ideas what could be the issue?
Thanks
Hetal
Three thoughts:
You cannot use the same long press gesture recognizers for two controls. You have to create a separate gesture recognizer for each control.
It would appear that the gesture recognizers get reset when you start editing in text field (assuming you allow editing in the text field). I assume you allow editing of the text field, and, if so, I believe that you have to set a delegate that will disable the long gesture recognizer that is not your own. (You can do that, for your long press gesture recognizer, subclass it as, say CustomLongPressGestureRecognizer, use that for your text field's gesture recognizers and then you can disable any UILongPressGestureRecognizer objects that are not your own CustomLongPressGestureRecognizer.)
I infer from your code that you're not using storyboards and prototype cells, because in that scenario, cell is never nil and your if statement would never end up invoking your code. But if you're using NIBs or not using prototype cells, then you should be fine on this point.

Detecting swipe gestures on UITableViewCell inside UIScrollView

I am hoping someone will be able to help me with a problem that is doing my head in at the moment!
Given the following view hierarchy
I want to be able to detect swipe gestures on my custom UITableViewCell.
I have subclassed the UIScrollView and have a hitTest:withEvent: method that checks whether I am touching the tableview cell (or its content) or not, in which case I set the following scroll view properties:
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* result = [super hitTest:point withEvent:event];
if ([result.superview isKindOfClass:[UITableViewCell class]] || [result.superview tag] == SUBVIEW_TAG)
{
self.canCancelContentTouches = NO;
self.delaysContentTouches = YES;
} else {
self.canCancelContentTouches = YES;
self.delaysContentTouches = NO;
}
return result;
}
I have also implemented:
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
if (view.tag == SUBVIEW_TAG || [[view superview] isKindOfClass:[UITableViewCell class]])
return NO;
return YES;
}
And am returning NO in case the view being touched is the table view cell.
These methods are all getting called and performing their actions as expected, but I am still unable to stop the UIScrollView from "hogging" the swipe gesture.
The interesting thing is that if I include the UIView that contains the tableview and cell on both of the methods above (the one with SUBVIEW_TAG) it works perfectly so I am guessing it must be something to do with the fact that UITableView inherits from UIScrollView.
My main goal is to be able to swipe on the cell to reveal more options for the cell. A horizontal swipe anywhere else on that view would be captured by the scroll view and shift the content horizontally as per its normal behaviour.
Any ideas would be very much appreciated!
Thanks!
Rog
I had a similar problem with a swipe detect for a component inside a scrollview and I was able to resolve it with
[scrollView.panGestureRecognizer requireGestureRecognizerToFail:swipeGesture]
Where scrollView is the scroll view object that acts like container and swipeGesture is the component swipe gesture object inside scrollview.
So, you can define a swipe for the cell object like this (for right swipe in the example, custom it as you want)
UISwipeGestureRecognizer* rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(yourMethod)];
[rightSwipeRecognizer setDirection:UISwipeGestureRecognizerDirectionLeft];
[cell addGestureRecognizer:rightSwipeRecognizer];
and then do
[scrollView.panGestureRecognizer requireGestureRecognizerToFail:rightSwipeRecognizer]
The documentation of requireGestureRecognizerToFail says:
This method creates a relationship with another gesture recognizer
that delays the receiver’s transition out of
UIGestureRecognizerStatePossible. The state that the receiver
transitions to depends on what happens with otherGestureRecognizer:
If otherGestureRecognizer transitions to
UIGestureRecognizerStateFailed, the receiver transitions to its normal
next state.
if otherGestureRecognizer transitions to
UIGestureRecognizerStateRecognized or UIGestureRecognizerStateBegan,
the receiver transitions to UIGestureRecognizerStateFailed.
An example where this method might be called is when you want a
single-tap gesture require that a double-tap gesture fail.
Availability Available in iOS 3.2 and later.
Hope helps!
The solution is pretty simple. All you need to do is add UIScrollView inside you UITableViewCell. It will prevent "hogging" effect during swipe gesture.

Resources