UILongPressGestureRecognizer on UIButton not working - ios

I have a longpress gesture recognizer that I create in ViewDidLoad then attach to a button like this, the button is created in the storyboard and linked to my class.
UILongPressGestureRecognizer *hold = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(secretChange:)];
hold.minimumPressDuration = 5.0;
hold.delegate = self;
[_button addGestureRecognizer:hold];
The class conforms to the GestureRecognizer protocol and I have my selector here
- (void)secretChange:(UILongPressGestureRecognizer *)sender {
// Some stuff
NSLog(#"Secret");
}
The selector is not being called and I cannot figure out why, this seems to be the code everyone gives out on the internet, I have tried removing the minimum duration to make sure I didn't accidentally set it ridiculously long
UPDATE: I am actually adding this gesture recognizer to multiple buttons like this
[_button1 addGestureRecognizer:hold];
[_button2 addGestureRecognizer:hold];
[_button3 addGestureRecognizer:hold];
What is happening is the gesture recognizer is only being applied to the last button I add it to. How do I get the gesture recognizer added to ALL the buttons? Do I need to make a new one for every button?

You should have three instance of UILongPressGestureRecognizer.
Before add a gesture recognizer to a new view, the addGestureRecognizer method will remove the gesture recognizer from the view it has been attached to.

Related

UITapGestureRecognizer and touchesBegan for same view

I want to have UITapGestureRecognizer in a view and touchesBegan in its childview, but the problem is when UITapGestureRecognizer is recognized touchesBegan is not called.
Is it doing this is fine? Or should I need to take another approach ?
Edit : Solved. Setting cancelsTouchesInView property of UITapGestureRecognizerdid the trick for me. By default it is false, so touchesBegan isn't called.
Please find out where are you wrong,
This is a step by step guide on how to implement gesture recognizers in your class:
Conform your class to UIGestureRecognizerDelegate protocol.
Instantiate the gesture recognizer. For example, to instantiate a UITapGestureRecognizer, we will do:
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapFrom:)];
Here, action is the selector which will handle the gesture. Here, our selector handleTapFrom will look something like:
- (void) handleTapFrom: (UITapGestureRecognizer *)recognizer
{
//Code to handle the gesture
}
The argument to the selector is the gesture recognizer. We can use this gesture recognizer to access its properties, for example, we can find the state of the gesture recognizer, like, UIGestureRecognizerStateBegan, UIGestureRecognizerStateEnded, etc.
Set the desired properties on the instantiated gesture recognizer. For example, for a UITapGestureRecognizer, we can set the properties numberOfTapsRequired, and numberOfTouchesRequired.
Add the gesture recognizer to the view you want to detect gestures for. In our sample code (I will be sharing that code for your reference), we will add gesture recognizers to an imageView with the following line of code:
[self.imageView addGestureRecognizer:tapGestureRecognizer];
After adding the gesture recognizer to the view, set the delegate for the gesture recognizer, i.e. the class which will handle all the gesture recognizer stuff. In our sample code, it would be like:
tapGestureRecognizer.delegate = self;
Note: Assign the delegate after adding the gesture recognizer to the view. Otherwise, the action method won’t be called.

iOS gestureRecognizer not handled subviews

i have the following problem: in my iphone app i have a UIView that holds 0 to several subviews. Those subviews may overflow the parent and therefore be hidden and all of them are UIButtons. I added a UISwipeGestureRecognizer to the UIView to move the buttons around which works great. However it only works when the gesture is done on background, the UIButtons interfere with the gesture recognizer.
How i can i pass the gesture through? Btw. i still need the tap of the Buttons.
Thanks!
EDIT:
I tried to add the gesture recognizer to the UIButtons too, but it is not triggered... Although performing the swipe gesture prevents the UIButton from going to highlighted state it doesn't trigger the gesture. I added setDelaysTouchesBegan:YES as suggested in UIButton and Swipe Gesture. That's how i do it right now:
UIButton *breadcrumb = [UIButton buttonWithType:UIButtonTypeCustom];
[breadcrumb setImage:[UIImage imageNamed:#"Next"] forState:UIControlStateNormal];
[breadcrumb setTitle:title forState:UIControlStateNormal];
[breadcrumb.titleLabel setFont:[UIFont systemFontOfSize:12.0f]];
[breadcrumb sizeToFit];
[breadcrumb setTag:level];
UISwipeGestureRecognizer *gr = [[UISwipeGestureRecognizer alloc] init];
[gr setDelegate:self];
[gr setDirection:UISwipeGestureRecognizerDirectionRight];
[gr setDelaysTouchesBegan:YES];
[self.tableView addGestureRecognizer:gr];
[breadcrumb addGestureRecognizer:gr];
EDIT 2:
I have now subclassed UIButton and initilizing it now like so: [BreadcrumbButton buttonWithType:UIButtonTypeCustom]. In the initializer i added the button itsself as a listener to all touch events [self addTarget:self action:#selector(eventReceiver:) forControlEvents:UIControlEventAllTouchEvents]; to inspect whats going on.
- (void)eventReceiver:(UIButton *)btn {
NSLog(#"Reveived event: %# ---------------", btn);
for(UIGestureRecognizer *gr in ev.gestureRecognizers) {
NSLog(#"Gesture: %#", gr);
}
}
What i see is that a) the button has just one gesture recognizer added and b) that this UISwipeGestureRecognizer jumps to state Possible during swipe but does not forward to its delegate methods.
You would have to subclass the UIButton and over ride the tap delegate callback and forward this call to whatever is handling a UISwipeGestureRecognizer. Unless you add the gesture recognizer on the UIButton, it will always call it's touch handler before the view behind it. You can also explicitly tell the button to not handle it's touch events thus passing the touch event down the chain (via userInteractionEnabled), but as you've already stated you do not want this. The best way to go about this would be by creating a subclass of UIButton and handling the touch events there and/or forwarding the events using delegation. Pressing the button is a touch event, so you may just want to add a tap gesture recognizer to the button and call the IBAction from that and then have the swipegesturerecognizer forward a delegate call.

addTarget:action:forControlEvents: ignored when interacting with separate UITapGestureRecognizer

I'm somewhat new to iOS programming
I have some code (abridged) that looks like the following
UIView *someSubView = [[UIView alloc] initWithFrame:...];
[self addSubView:someSubView];
[someSubView addTarget:self action:#selector(_handleTapOnView:) forControlEvents:UIControlEventTouchUpInside];
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(_handleTap:)];
_tapGestureRecognizer.delegate = self;
[self.view addGestureRecognizer:_tapGestureRecognizer];
Unfortunately the gesture recognizer triggers and my views addTarget call does not. I've tried commenting out the gesture recognizer code and it works, so I know its not the call to addTarget on the subview.
I solved this initially by using the gestureRecognizer:shouldReceiveTouch: and doing a hit test for the sub view, but I feel like I'm missing some fundamental understanding here that wouldn't require me adding a manual hit test.
Its important to note that I don't want the code in the _handleTap in the _tapGestureRecognizer to execute when I have tapped on my subview.
Any guidance here? Thanks!
Try using:
_tapGestureRecognizer.cancelsTouchesInView = NO;
otherwise the gesture recogniser will intercept the touches and will not forward them further (in other words, the gesture recogniser gets the touch, handles it, and since it cancel it, no other object gets the touch). By not cancelling, the touch is forwarded for any other object (recognisers or views) to handle it.

Adding gestures for UIImageView and UIView at one ViewController

Newbie question.
In IB I added UIImageView to scene and set few gestures for it in -viewDidLoad this way:
image.userInteractionEnabled = YES;
image.multipleTouchEnabled = YES;
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(controlPan:)];
[image addGestureRecognizer:pan];
pan.delegate = self;
// and few others gestures same way
...
and gestures worked fine. After that in IB I added UIView to the same scene and implement gestures absolutely identically to previous code, again in -viewDidLoad. But after that gestures stop working for both UIView and UIImageView. Do I need to make .h and .m for this view and to implement gesture recognizers there, or reason can be in something else?
If you have same handler method you need to make distinction from which object gesture came, so you can properly handle action. If you set different handler methods for every object you dont have to care from which object gesture was invoked.

Homemade tap gesture recognizer for iOS

I'd like to code my own tap gesture recognizer, to detect the number of taps and number of touches (I don't want to use the iOS tap gesture recognizer because I want to extend it later in various other manners) ;
I tried the following : use the first motionBegin number of touches as the numberOfTouches of the tap, increment the numberOfTaps, and start the tap detection timer to detect the tap gesture if no new taps has been seen in a while
The problem is that one quickly realises that when doing a double-touch tap gesture, iOS either correctly detects one motionBegin with a double touch, or two quick one touch events. I guess a correct implementation should try to detect those quick one touch events that happen closely, but I'm wondering if there is a better way to implement the gesture recognizer.
Someone knows how the iOS tap gesture is implemented?
1. Add UIGestureRecognizerDelegate in your .h file. like
#interface finalScreenViewController : UIViewController <UIGestureRecognizerDelegate>
{
// do your stuff
}
2. Create a view in your viewDidLoad method (or any other method) you wanna to add the gesture in your .m file
ex
UIView * myView=[[UIView alloc]init];
myView.frame=CGRectMake(0,0.self.view.frame.size.width,self.view.frame.size.height);
[self.view addSubView: myView];
UITapGestureRecognizer *letterTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapMethod:)];
letterTapRecognizer.numberOfTapsRequired = 1;
[myView addGestureRecognizer:letterTapRecognizer];
3. you can get view by
- (void) tapMethod:(UITapGestureRecognizer*)sender {
UIView *view = sender.view;
NSLog(#"%d", view.tag);//By tag, you can find out where you had tapped.
}

Resources