I have a UIPageViewController and each Page contains multiple UIViews on the page, each UIView allows Pan gesture after a longPress gesture, I use the following delegate in the contentVC, but it appears the pageVC doesn't care my restriction below and it continue to flip the page! do I have to do anything to disable the page turning while I am in panning? (the last resort will be setting an variable at the PageVC like a canTurn, and set it to NO while the panning is in action....
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] &&
[otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
return YES;
}
return NO;
}
You should add the -gestureRecognizer:shouldReceiveTouch: method in the PageVC itself, or if you dont wanna add it in the PageVC itself you could let a delegate handle it
Like:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if(someCase)
{
return yes;
}
return no;
}
or
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return [delegate shouldHandle:.....];
}
Related
I have a gesture recognizer that I've made on a calculator. It's connected to an action that is activated upon a user's double tap. I connected the gesture recognizer to the main view of the view controller, however the gesture recognizer is also applied to my buttons. So if the user quickly types 11, they'll press 1 two times fast and accidentally activate a function that they don't want to. How do I make it so that the UIGestureRecognizer doesn't act upon buttons? I want to keep the double-tap gesture. I don't want to change it to a two finger tap or something odd like that. However, if there's no other way (which I doubt there is), I could do that.
Try this:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ((touch.view == yourButton)) {
return NO;
}
return YES;
}
This will be called every time the gesture is recognized, and it will ignore the gesture is the view is your button.
You should adopt UIGestureRegconizerDelegate protocol in your ViewController.h
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>
#end
in your ViewController.m, implement this method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UIControl class]]){
return NO;
}
return YES;
}
and yourGestureRecognizer.delegate = self //your view controller.
Building on Antonio's answer, you could give all of your tags to make this easier. Presumably, your calculator has more than just one yourButton. Suppose all your buttons have a tag larger than 100:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
if ((touch.view.tag > 100)) {
return NO;
}
return YES;
}
This is cleaner than checking the class of the view. You could now have controls where you allow the gesture to be recognised anyway.
I have a button and a gesture recognition and when the button is pressed only one method should be called.
Most cases only the gesture recognition is being called which is fine but every no and then the button gets called to which causes problems.
I have a view and then a scroll view. All my buttons are on the scroll view
you can implement this in your view controller and assign it to the delegate of the gesture recognizer.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
CGPoint p = [gestureRecognizer locationInView:self.view];
UIView *view = [sefl.view hitTest:p withEvent:nil];
if ([view isKindOfClass:[UIButton class]]) {
return NO;
}
return YES;
}
or you can implement - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch with similar logic if gestureRecognizerShouldBegin: does not suit.
For example, I have a button, when click this button, it call an action: doAction1.
And an View: when touch in it, it call an action doAction2.
When clicked in this button, I touched in view, too.
Is it have any property to set priority to call doAction1 or doAction2?
I assume that you you put a Tapgesturerecogniyer to container view.You can ignore the tap gesture if user has tapped on the button.Just overwrite the fooling method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// test if touched view is unbutton
if ([touch.view isKindOfClass:[UIButton class]])
{
return NO; // ignore the touch
}
return YES;
}
I'm building an iPhone app that would let the user rearrange some of the UI elements on the screen.
How can I add a tap gesture recognizer and a long press gesture recognizer to the same UIView? When I lift up the finger from the long press, the tap gesture recognizer fires. How can I temporarily disable the tap gesture recognizer or prevent it from firing when the user is performing a long press?
Thank you!
To allow both gestures to work together, implement the following delegate method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
To make it so that the long press has first priority, do:
[tapGesture requireGestureRecognizerToFail:longPress];
To combine successfully both you need:
1º Add to interface gesture delegate at header
#interface ViewController : ViewController <UIGestureRecognizerDelegate>
2º Create gesture events and add to a view into source file:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(touch:)];
[tap setNumberOfTapsRequired:1]; // Set your own number here
[tap setDelegate:self]; // Add the <UIGestureRecognizerDelegate> protocol
UILongPressGestureRecognizer *longTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTouch:)];
[longTap setNumberOfTapsRequired:0]; // Set your own number here
[longTap setMinimumPressDuration:1.0];
[longTap setDelegate:self]; // Add the <UIGestureRecognizerDelegate> protocol
[tap requireGestureRecognizerToFail:longTap]; // Priority long
[self.view addGestureRecognizer:tap];
[self.view addGestureRecognizer:longTap];
3º Add callbacks in source file:
- (void) touch: (UITapGestureRecognizer *)recognizer
{
CGPoint location = [recognizer locationInView: self.HUDview];
if (recognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"touch UIGestureRecognizerStateBegan");
}
if (recognizer.state == UIGestureRecognizerStateEnded)
{
NSLog(#"touch UIGestureRecognizerStateEnded");
//NSLog(#"Position of touch: %.3f, %.3f", location.x, location.y); // Position landscape
}
}
- (void) longTouch: (UILongPressGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"longTouch UIGestureRecognizerStateBegan");
}
if (recognizer.state == UIGestureRecognizerStateEnded)
{
NSLog(#"longTouch UIGestureRecognizerStateEnded");
}
}
4º Set gesture recognizer available:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
As an alternative approach, don't have two separate recognisers - just use the LongPress recogniser for both events:
Configure as follows:
UILongPressGestureRecognizer* longPress = [ [ UILongPressGestureRecognizer alloc ] initWithTarget:self.nextResponder action:#selector(longPressEvent:)];
categoryPanelDrag.minimumPressDuration = 0.0;
Then handle as follows:
- (BOOL)longPressEvent:(UILongPressGestureRecognizer *)gesture {
// _dragStarted is a class-level BOOL
if(UIGestureRecognizerStateBegan == gesture.state) {
_dragStarted = NO;
}
if(UIGestureRecognizerStateChanged == gesture.state) {
_dragStarted = YES;
// Do dragging stuff here
}
if(UIGestureRecognizerStateEnded == gesture.state) {
if (_dragStarted == NO)
{
// Do tap stuff here
}
else
{
// Do drag ended stuff here
}
}
return YES;
}
I did try moby and journeyman's approach but somehow they didn't fit my project well, so I solved like below,
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
NSLog(#"%# %ld",touch.description, touch.phase);
[self performSelector:#selector(checkTouch:) withObject:touch afterDelay:0.5];
return YES;
}
and
- (void)checkTouch:(UITouch *)touch{
NSLog(#"touch phase = %ld",touch.phase);
if (touch.phase == UITouchPhaseStationary) {
//still holding my hand and this means I wanted longPressTouch
}
if (touch.phase == UITouchPhaseEnded){
//I released my finger so it's obviously tap
}
}
It could be simpler solution but of course it depends to project.
You could take care of it in the code, that during the long press, set a flag, and if the tap gets called while the flag is true or whatever then don't execute the tap code and reset the flag. I don't know a better way
I've seen some threads about how to dismiss the Keyboard when a UITextField loses focus, but it did not work for me and I don't know how. The "touchesBegan:withEvent:" in the following code, never gets called. Why?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([self.textFieldOnFocus isFirstResponder] && [touch view] != self.textFieldOnFocus) {
[textFieldOnFocus resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}
P.S.: This code has been inserted in the view controller which has a UITableView. The UITextField is in a cell from this table.
So, my opinion is: this method is not being called, cause the touch occurs on the UITableView from my ViewController. So, I think, that to I should have to subclass the UITableView, to use this method as I have seen on other Threads, but it may have a easier way.
Could you please help me? Thanks a lot!
Make sure you set the delegate of the UITextField to First Responder in IB. And I just put a custom (invisible) UIButton over the screen and set up an IBAction to hide the keyboard. Ex:
- (IBAction)hideKeyboard {
[someTextField resignFirstResponder];
}
With that hooked up to a UIButton.
Here is my solution, somewhat inspired by several posts in SO: Simply handle the tap gesture in the context of the View, the user is 'obviously' trying to leave the focus of the UITextField.
-(void)handleViewTapGesture:(UITapGestureRecognizer *)gesture
{
[self endEditing:YES];
}
This is implemented in the ViewController. The handler is added as a gesture recognizer to the appropriate View in the View property's setter:
-(void) setLoginView:(LoginView *)loginView
{
_loginView = loginView;
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self.loginView action:#selector(handleTapGesture:)];
[tapRecognizer setDelegate:self]; // self implements the UIGestureRecognizerDelegate protocol
[self.loginView addGestureRecognizer:tapRecognizer];
}
The handler could be defined in the View as well. If you are unfamiliar with handling gestures, see Apple's docs are tons of samples elsewhere.
I should mention that you will need some additional code to make sure other controls get taps, you need a delegate that implements the UIGestureRecognizerDelegate protocol and this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UIButton class]]) // Customize appropriately.
return NO; // Don't let the custom gestureRecognizer handle the touch
return YES;
}
-(void)touchesEnded: (NSSet *)touches withEvent: (UIEvent *)event
{
for (UIView* view in self.view.subviews)
{
if ([view isKindOfClass:[UITextField class]])
[view resignFirstResponder];
}
}