Long press and pan gesture in UICollectionView - ios

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;

Related

UICollectionView within UIScrollView: Long Press

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.

UISlider in UITableView not responding to swipe gesture

I try to insert UISlider to UITableViewCell, but swipe gesture doesn't work correctly. For sliding needed hold and move the thumb, but i want to get swipe gesture without holding. I think tableview's own gestures not allow do this, but i don't know how to disable it.
Use - gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
to set the property to YES. Then you can add a check in a function to decide which gesture to act on.
I've encountered the same problem recently. It happens for me in static cell of UITableViewController, it's instantiated from storyboard. I have found an ugly workaround, but will be happy to see a better solution for this.
So i've disabled all gesture recognisers of self.view and self.view.superview of UITableViewController:
- (void)disableGestureRecognisersInView:(UIView*)view {
for ( UIView *subview in view.subviews ) {
for ( UIGestureRecognizer *rec in subview.gestureRecognizers ) {
rec.enabled = NO;
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self disableGestureRecognisersInView:self.view];
[self disableGestureRecognisersInView:self.view.superview];
}
And now UISlider works normally, didn't noticed any other problems because of this workaround too. But i still don't like it.

Get UITapGestureRecognizer to recognize touches when they begin?

Is there any way to get UITapGestureRecognizer to run on touch began?
I can't use touchesBegan because I am using a UITableView and the super view steals the event essentially.
I just want to detect when the screen is first touched. Why is this so difficult? Maybe I need a different solution than using tapgesturerecognizer?
You can use state property of UIGestureRecognizer to identify various states of any gesture -
#property(nonatomic,readonly) UIGestureRecognizerState state; // the current state of the gesture recognizer
So when the gesture begin, use something like this in your registered handler method -
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
// Do your stuff
}
You can add a tap gesture recognizer to the tableView in viewDidLoad like this:
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureRecognized:)];
[self.tableView addGestureRecognizer:tapGestureRecognizer];
Then implement this method:
- (void)tapGestureRecognized:(UITapGestureRecognizer *)tapGestureRecognizer {
NSLog(#"tap gesture recognized");
}
Just tested this out, and works fine. For every tap i get the log message on my console. Note that this prevents the tableview from receiving the taps, other gestures will just be handled by the table view as usual.
You need to set delaysContentTouches = NO

Disable Gesture Recognizer for UIImageView in iPad app

I have a PageControl and each page (ViewController) has different number of imageviews (UIImageView), which are created dynamically.
Each imageview is assigned a gesture recognizer (tapped or move). Since these are inside a PageControl, I would like to enable/disable the gesture recognizer so it won't interfere with the swipe to page events.
I know that there's a removeGestureRecognizer method, but I don't want to remove and attach that each time. Is there an equivalent for just enabling and disabling?
Thanks
You can use enable or disable properties of the UIGestureRecognizer like :
swipeGestureRecognizer.enabled = NO;
or you can use the gesture recognizer method return null if you don't want touches
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch;
If you want to disable all the gestures at the same time, you can do like
imageView.userIntractionEnabled = NO;
if you want to disable only one gesture recognizer, then
NSArray *gestures = imageView.gestureRecognizers;
for(UIGestureRecognizer *gesture in gestures)
{
if([gesture isKindOfClass: [UITapGestureRecognizer class]])
{
gesture.enabled = NO;
}
Can you disable userInteractionEnabled for that UIImageView ? You could do it in Interface Builder if you are doing it that way or you could programatically set this like so - imageView.userInteractionEnabled = NO; Hope this helps...

Gesture recognition with UIWebView

I have set up some gesture recognition in an app that I'm building. One of the gestures is a single finger single tap, which hides the toolbar at the top of the screen. Works great except for one thing: a tap on a link causes the toolbar to go away, too.
Is it possible to detect a tap that was not a tap on a link? Could I do this by seeing where the tap occurred, and only take action if it didn't occur on an html link? Is this is possible, a pointer to how to determine if a link was tapped would be helpful.
Per Octys suggestion, I did attempt to wrap the UIWebView inside a UIView. I'm using interface builder, so I inserted a view in the hierarchy, and made the UIWebView a "child" of the new UIView. The hierarchy looks like this now:
I added an IBOutlet for the view in my view controller, and linked it up in interface builder.
I changed the gesture recognizer setup to look like this:
UITapGestureRecognizer* singleTap=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTouchesRequired=1;
singleTap.delegate=self;
[self.UIWebViewContainer addGestureRecognizer:singleTap];
[singleTap release];
This code resides in viewDidLoad.
As before, the code correctly sees a single finger single tap, but a tap on a link in the UIWebView also causes the toolbar to go away. I only want the toolbar to go away if a link was NOT tapped.
Anyone have any suggestions?
Thank you.
Chris
Thanks
Chris
Try wrapping your UIWebView in a UIView container and set your gesture recognizers on the container view. Touch events that are not handled by the UIWebView will be passed up the view hierarchy and be intercepted by your container view, assuming it implements the appropriate handlers (and it is these handlers that should implement the code for hiding the toolbars...).
OK, so one "hack-ish" workaround is to make the view controller which houses the UIWebView a delegate of the gesture recognizer that you instantiate(UIGestureRecognizerDelegate) I am usually not a fan of solutions like this one, but...
Assign the gesture recognizer to the view that wraps you web view, and set it's delegate to self.
then in the delegate method gestureRecognizer:shouldRecieveTouch method, set the state to indicate the there was a tap event,
Return NO from the delegate method so the event propagates down the responder chain to the UIWebView.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
_userTapped = YES;
[self performSelectorOnMainThread:#selector(hideMenuIfNotLink) afterDelay:??.?];
//??.?? amount of time to lapse to see if shouldStartLoadWithRequest gets called.
return NO;
}
-(void)hideMenuIfNotLink{
if(_userTapped)
//hideMenu
}
Now, in your UIWebViewDelegate shouldStartLoadWithRequest (which gets called when a user has in fact clicked a link)
if(_userTapped){
_userTapped = NO;
//possibly code to reshow or verify keep showing menu
}
You can use the UIWebViewDelegate protocol's -webView:​shouldStartLoadWithRequest:​navigationType: method.
If the navigationType is UIWebViewNavigationTypeLinkClicked, you can get the URL for the click by checking [request URL].
I've been looking for the same thing and found this: There is an iOS specific property that disables the callout when you hold your finger on a link. You add this into the styling (CSS) of your urls.
-webkit-touch-callout: none;
This worked for me.try adding the below line of code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
I was having the same problem. This solution worked for me:
1) make sure to add the protocol to your interface: UIGestureRecognizerDelegate
for example:
#interface ViewController : UIViewController _SlideViewProtocol, UIGestureRecognizerDelegate_
2) add this line of code
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
}
3)
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(nextSlide)];
swipeGesture.numberOfTouchesRequired = 1;
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft);
swipeGesture.cancelsTouchesInView = YES;
[swipeGesture setDelegate:self];
[self.view addGestureRecognizer:swipeGesture];

Resources