Getting the UIButton that was double-tapped from UIGestureRecognizer's action method - objective-c

I wrote a fairly long action method connected to several UIButtons, and now I've realised I would like to have something different happen if I tap one of the buttons twice. So I am setting up two gesture recognizers:
UITapGestureRecognizer *tapOnce = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnce:)];
UITapGestureRecognizer *tapTwice = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapTwice:)];
tapOnce.numberOfTapsRequired = 1;
tapTwice.numberOfTapsRequired = 2;
[tapOnce requireGestureRecognizerToFail:tapTwice];
[self.mybutton addGestureRecognizer:tapOnce];
[self.mybutton addGestureRecognizer:tapTwice];
then, I implement the methods:
- (void)tapOnce:(UIGestureRecognizer *)gesture{
//Do what you were already doing
}
- (void)tapTwice:(UIGestureRecognizer *)gesture{
// Some new functionality
}
Now, I don't have a problem with the new functionality. Where I get stuck is trying to get the tapOnce: method to do what my button was already doing. I need to know which button was tapped, so I can't use this:
[myButton sendActionsForControlEvents: UIControlEventTouchUpInside];
I also tried the old:
for (button in myArrayOfButtons){
[button sendActionsForControlEvents: UIControlEventTouchUpInside];
}
No luck either.
Then I went the way of actually creating a separate method for the implementation of my button, so what was:
- (IBAction)buttonPressed:(id)sender {
//my functionality...
}
became:
- (IBAction)buttonPressed:(id)sender {
[self myMethodwithSender:sender];
}
-(void)myMethodwithSender: (id)sender{
// my functionality
}
So that worked in itself, but when I try to put the tap once and twice into play I get stuck. I tried putting my new method in the method for tap once:
- (void)tapOnce:(UIGestureRecognizer *)gesture{
[self myMethodwithSender:sender];
}
but of course there is no sender in this method so it doesn't work (right?)
Then I tried changing this:
UITapGestureRecognizer *tapOnce = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnce:)];
to this:
UITapGestureRecognizer *tapOnce = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(myMethodwithSender:)];
Which doesn't work either. So I am not sure how to do this. Any suggestions welcome.

With:
- (void)tapOnce:(UIGestureRecognizer *)gesture{
[self myMethodwithSender:sender];
}
If myMethodWithSender doesn't use sender, you can send nil. If it needs it to be the button, gesture.view should be that button (if you attached the recognizer to the button)

Related

Accessing tag value for UIImageView in UITapGesture Handler

I have a UITapGesture attached to an image view. I'd like to reuse the same gesture across a couple of images. To do that the handler method needs to be able to recognize from which image the tap is coming. The method below attempts to access the tag value for the sender image view. I based it on the answer to this question https://stackoverflow.com/a/4425059/549273. However, I'm getting an error in the debugger that reads "unrecognized selector sent to instance". I tried it exactly as written in the answer and I also tried it with the sender appended to the method as a parameter as shown below. Netiher approach works. Can someone show me what I did wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
topLeftImage.userInteractionEnabled = YES;
[topLeftImage addGestureRecognizer:singleTap];
}
- (void)handleSingleTap:(UITapGestureRecognizer*)gestureView andSender:(id)sender {
switch (((UIGestureRecognizer *)sender).view.tag)
{
case 0:
NSLog(#"zero");
case 1:
NSLog(#"one");
}
}
From the UIGestureRecognizer class reference:
The action methods invoked must conform to one of the following
signatures:
(void)handleGesture;
(void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;
Your method (- (void)handleSingleTap:(UITapGestureRecognizer*)gestureView andSender:(id)sender) does not conform to either signature. Beyond this, when you create your gesture recognizer, you are using the action #selector(handleSingleTap:) which does not match up with this function, so it should never even be called. Try this instead:
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
topLeftImage.userInteractionEnabled = YES;
[topLeftImage addGestureRecognizer:singleTap];
}
- (void)handleSingleTap:(UIGestureRecognizer*)gestureView {
switch (gestureView.view.tag)
{
case 0:
NSLog(#"zero");
case 1:
NSLog(#"one");
}
}
Agree with #Inafziger (as usual), but here's a better way to do it: Place distinct gesture recognizers on the distinct views.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[topLeftImage addGestureRecognizer:singleTap];
// just like first as far as the target and selector, but a distinct object
singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[bottomRightImage addGestureRecognizer:singleTap];
// and so on ...
Now, the handler can just ask the gr to which view it is attached. No tags, no switch statement.
- (void)handleSingleTap:(UIGestureRecognizer*)gr {
UIImageView *theTappedView = (UIImageView *)gr.view
}

how to call a tapGesture IBAction from code in obiective-c

i have a view and i add tapGesture with a handle function to this view,
and i want to call the tap action from code,for calling the handle function ....
-(IBAction) handleTapGesture:(UIGestureRecognizer *) sender
how can i do that???
now i can get this view, how to call the tap action from code?
i find some function about it,but it doesnot work well .
like the : UIControl sendActionsForControlEvents / UIView performSelector ...
What about
[theView handleTapGesture:nil];
?
IN your view controller,put this code
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired=1;
[self.currentImageView addGestureRecognizer:tapGesture];
[tapGesture release];
then write your code for tap function in
-(void) handleTapGesture:(UITapGestureRecognizer *)sender {
}

iOS - increase partial curl tap area to dismiss modal

Is there a way to do this? Like tapping on any part of the screen dismisses the partial modal curl.
I thought about an invisible button, but that still doesn't cover the whole curl area.
Add gesture recognizers to your main view in viewDidLoad
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(getDismissed)];
UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(getDismissed)];
swipeRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.numberOfTouchesRequired = 1;
tapRecognizer.delegate = self;
[self.view addGestureRecognizer:tapRecognizer];
[self.view addGestureRecognizer:swipeRecognizer];
-(void)getDismissed
{
// call dismissViewControllerAnimated:completion: by the presenting view controller
// you can use delegation or direct call using presentingViewController property
}
Then exclude in view that you don't want to trigger the dismissal
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
// touching objects of type UIControl will not dismiss the view controller
return ![touch.view isKindOfClass:[UIControl class]];
}

Two finger tap on UIButton

I've got a UIButton in my application called myButton. I'd like to react to a single finger tap and a two finger tap on the button differently. However, from what I understand UIButton objects are only able to detect single finger touches touchDown, touchUpInside, etc. After doing some research, it looks like I'll have to use the touchesBegan method and just check to see if both of the fingers are within myButton frame. Is there any easier way to do this? Thanks!
Yes it is! By using UITapGestureRecognizer you can do something like this
- (void)viewDidLoad {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)]
tap.numberOfTapsRequired = 2;
[myButton addGestureRecognizer:tap];
[tap release];
}
- (void)tap:(UITapGestureRecognizer *)gesture {
NSLog(#"Tap!");
}

UIKeyboardTypeNumberPad dismiss keyboard

How is a user suppose to indicate that he/she is done typing if the keyboard is of type UIKeyboardTypeNumberPad? There's no return/done button so how do I know the user wants to dismiss the keyboard?
Thanks
After researching this problem for a while, I found no really satisfactory answers. Some solutions hack a "Done" button, but that doesn't work well for localized applications. My apps don't use any words so I definitely don't want a "Done" button.
As mentioned by taskinoor it is convenient for editing to end if the view is touched elsewhere. That's what I did, and here is code showing the details:
Creating the textField programmatically:
aTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
[aTextField addTarget:self action:#selector(c1Update) forControlEvents:UIControlEventEditingDidEnd];
aTextField.keyboardType = UIKeyboardTypeNumberPad;
[yourView addSubview:aTextField];
c1Value = aTextField; // I like to keep a pointer for UI updates, alpha etc.
What happens in c1Update:
- (void)c1Update {
[[self brain] setC1:[c1Value.text intValue]]; // update the model
}
Gesture recognizer on view:
- (void)viewDidLoad {
[super viewDidLoad];
[self updateViewColors];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTapped)];
tapRecognizer.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapRecognizer];
}
- (void) viewTapped {
if (c1Value.isFirstResponder) {[c1Value resignFirstResponder];} // dismisses keyboard, which causes c1Update to invoke.
}
You can either provide a cancel/hide button (outside the keypad) or hide that when touched anywhere outside the keypad. These two are common practices.
try this. it might help you
hide the keypad when touched the screen.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
}