I want to be able to make a gesture recognizer listening for a two finger swipe, anywhere on the screen.
Right now I have a UITableView in a sub-view that scrolls, of course, and it doesn't seem to pick up the UIGestureRecognizer that I set on the view. When you use the two fingers, it just scrolls...
Is there a way to make the entire view, maybe superview, listen for a two finger touch and when it recognizes it, it will instead of scrolling the table view, do what I want it to do?
EDIT: Heres my code but this is suposed to be a very general question. I just want to be able to have UIGestureRecognizers across the entire view, the whole thing.
navBarTitle.title = #"Crunch";
//opening the menuView from launch
//setup the customtable view as a subview in menuView
SDMenuViewController *mvc = [[[SDMenuViewController alloc] initWithNibName:#"SDNestedTableView" bundle:nil] autorelease];
[self addChildViewController:mvc];
[mvc didMoveToParentViewController:self];
[menuView addSubview:mvc.view];
[mvc.view setFrame:CGRectMake(mvc.view.frame.origin.x, mvc.view.frame.origin.y, mvc.view.frame.size.width, mvc.view.frame.size.height + 44)]; //add navBarHeight, for some strage reason
//add swipe down gesture on for the menu
UISwipeGestureRecognizer *swipeClose =[[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(closeMenu)] autorelease];
swipeClose.numberOfTouchesRequired = 2;
swipeClose.direction = UISwipeGestureRecognizerDirectionUp;
UISwipeGestureRecognizer *swipeOpen = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(openMenu)] autorelease];
swipeOpen.numberOfTouchesRequired = 2;
swipeOpen.direction = UISwipeGestureRecognizerDirectionDown;
for (UIGestureRecognizer* rec in menuView.gestureRecognizers) {
[rec requireGestureRecognizerToFail:swipeClose];
[rec requireGestureRecognizerToFail:swipeOpen];
}
for (UIGestureRecognizer* rec in mvc.view.gestureRecognizers) {
[rec requireGestureRecognizerToFail:swipeClose];
[rec requireGestureRecognizerToFail:swipeOpen];
}
[mvc.view addGestureRecognizer:swipeClose];
[mvc.view addGestureRecognizer:swipeOpen];
[self.view addGestureRecognizer:swipeClose];
[self.view addGestureRecognizer:swipeOpen];
Maybe I did not explain my question clearly. But for what I was doing this ended up working, and maybe it will help other people in the future:
Two finger swipe in UIScrollview for iPad application
you can try to do something like this:
UISwipeGestureRecognizer* p = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(actionPan:)];
p.numberOfTouchesRequired = 2;
for (UIGestureRecognizer* rec in tableView.gestureRecognizers) {
[rec requireGestureRecognizerToFail:p];
}
[self.view addGestureRecognizer:p];
hope that will help
//In view did load
[self.view setMultipleTouchEnabled:YES];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([[event touchesForView:self.view] count] > 1) {
NSLog(#"%d active touches",[[event touchesForView:self.view] count]) ;
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:swipeGesture];
}
}
-(void)handleSwipeGesture:(UISwipeGestureRecognizer *) sender
{
//Gesture detect - swipe up/down , can be recognized direction
if(sender.direction == UISwipeGestureRecognizerDirectionUp)
{
// do some thing...
}
}
i Hope this would solve your problem. and in touches enabled make the count equal to 2 or any number of touches.. :) feel free to ask if you have any doubts
Add another view with frame of self.view over self.view like "viewForGesture" and add gesture recognizer on that view like
UIView *viewForGesture = [[ [UIView alloc]initWithFrame:self.view.frame] autorelease];
[viewForGesture setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:viewForGesture];
.
.
.
[viewForGesture addGestureRecognizer:swipeOpen];
[viewForGesture addGestureRecognizer:swipeClose];
There's two way of making UIView detecting touch. The approach you defined and want that's UIGestureRecognizer, that answer already given by Ezeki.
Another approach you can use to detect touch is to override UITouch delegates.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if(touch.tapCount==2)
{
//Do something ... (Here, you can also check for the object which touched.)
}
}
Related
I have a tutorial for my app, which should display only the first time the app is opened and should be tapped to dismiss.
I am initializing a UITapGestureRecognizer in my viewDidLoad:
tapper_tut = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
tapper_tut.cancelsTouchesInView = FALSE;
[self.view addGestureRecognizer:tapper_tut];
and I have an IBAction to detect the tap and set the tutorial to hidden:
- (IBAction)dismiss_tut{
if (????????????????) {
_tutorial.hidden = YES;
}
}
But I have no idea what to put in the if statement condition, or if this is even that right way to go about this.
How would I dismiss a UIImageView on a tap?
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[self.view addGestureRecognizer:gr];
// if not using ARC, you should [gr release];
// mySensitiveRect coords are in the coordinate system of self.view
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer {
CGPoint p = [gestureRecognizer locationInView:self.view];
if (CGRectContainsPoint(mySensitiveRect, p)) {
NSLog(#"got a tap in the region i care about");
} else {
NSLog(#"got a tap, but not where i need it");
}
}
You can make viewDidLoad like this
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
/* Create the Tap Gesture Recognizer */
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleTaps:)];
/* The number of fingers that must be on the screen */
self.tapGestureRecognizer.numberOfTouchesRequired = 1;
/* The total number of taps to be performed before the gesture is recognized */
self.tapGestureRecognizer.numberOfTapsRequired = 1;
/* Add this gesture recognizer to the view */
[self.view addGestureRecognizer:self.tapGestureRecognizer];
}
To detect the taps you can make the method like this.
- (void) handleTaps:(UITapGestureRecognizer*)paramSender
{
NSUInteger touchCounter = 0;
for (touchCounter = 0;touchCounter < paramSender.numberOfTouchesRequired;touchCounter++)
{
CGPoint touchPoint =[paramSender locationOfTouch:touchCounter inView:paramSender.view];
NSLog(#"Touch #%lu: %#",(unsigned long)touchCounter+1, NSStringFromCGPoint(touchPoint));
}
}
you have to declare .h file as "UIGestureRecognizerDelegate"
you have getting tap of gesture as two way as given below steps.
1) Call delegate method of GestureRecognizer (not given action )
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:nil]; // not given action.
recognizer.numberOfTouchesRequired=1;// here how many tap you want set it
[self.view addGestureRecognizer:recognizer];
recognizer.delegate = self;
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
//whatever you want write code here
return NO;
}
2) given action
UITapGestureRecognizer *oneTouch=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(Addphoto)];
[oneTouch setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:oneTouch];
-(IBAction)Addphoto
{
//whatever you want write code here
}
may be it will help .
I think u need to detect the first time launch of the application which u can do with following
![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"]
Put this in your if statement .
How can I get touch event for UIScrollView.I have a UIViewController and I placed a scrollView in viewController.I need to add imageViews to scrollView and if a particular image is clicked it should redirect to its corresponding viewController.
I knew how to add touch event to a UIViewController.But that doesn't work for a scrollView.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch= [touches anyObject];
if ([touch view] == img1)
{
ViewController2 *viewController2=[[ViewController2 alloc]initWithNibName:#"ViewController2" bundle:nil];
[self presentViewController: viewController2 animated:YES completion:nil];
}
}
HOw can I get touches event for a scrollView ?
The only way to do this is by creating a custom UIScrollView Your custom UIScrollView will be a subclass of UIScrollView.
Also for more options you can check this
Set things like below:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[scrollView addGestureRecognizer:singleTap];
and you get the touch in:
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint=[gesture locationInView:scrollView];
}
You can use the ScrollViewDelegate and can use the function "ScrollViewDidScroll" for getting the scrollview scroll event.
Set up a tap gesture recognizer:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[scrollView addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint=[gesture locationInView:scrollView];
}
I am using :
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleViewClicked:)];
[tmp addGestureRecognizer:gestureRecognizer];
[gestureRecognizer release];
to get notification when a view(bigview for our example) i clicked(I have a lot of view), and in the front there is a UIView (a blank one) the he is in the front of the view (there is a reason why this view is in the front before al the views).
there is now a problem to get notification when tmp is tapped because the bigview is in the front.
there is any solution for something like this?
EDIT
In the bigview i have UISwipeGestureRecognizer:
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeRight:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[itemsView addGestureRecognizer:recognizer];
[recognizer release];
and if i make userInteractionEnabled in the bigview to NO he don't get notification on swipe
Two options:
A. Set userInteractionEnabled to NO on that big/blank view.
B. Implement pointInside:withEvent: on that big/blank view
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// UIView will be "transparent" for touch events if we return NO
return NO;
}
(as taken from allowing-interaction-with-a-uiview-under-another-uiview)
I have created some set of labels programmatically to display on the screen and i want after clicking on label some action should perform.
Please don't suggest me about UIButton. I want to do it for UILabel. After clicking on the label another detail view should appear.
Please help me to solve this problem without using Inteface Builder.
Finally i came up with the solution and i got the result
[titleLbl setUserInteractionEnabled:YES];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(labelButton:)];
[tapGestureRecognizer setNumberOfTapsRequired:1];
[titleLbl addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];
make IBoutlet of your label,
implement touchesBegin in your controller, pull out the CGPoint - touchCoordinate, check
CGRectContainsPoint(label.frame,touchCoordinate)
{
//you got the touch action on your label
}
In
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
.......
.......
CGPoint touch;//Touch Location
if(CGRectContainsPoint([objectOfLable frame], [touch locationInView:self.view ]) )
{
Do What you Want
}
}
Try This
Hola guys.
I'm experiencing a little problem with touch handling and UIResponder.
My goal is to manage a single touch (moved) to interact with different views.
I added a gesture recognizer to my UIImageView that send a simple message to my customViewController. It allocate and display a custom view (subclassing a UIButton) over the tapped UIImageView.
I would be able (without have to release the initial finger tap) to send touch movement to my new allocated custom button.
It seems that my UIImageView swallow my touch and so my new Button can't feel the finger movement.
I tried to resign first responder but it seems having no effect.
My custom Button work pretty good but only if I release the first tap and then tap again over the new displayer button.
Any suggests?
Thank you in advance.
Some code here:
Inside my viewController I attached a longPressGestureRecognizer to my profileImageView that draw a circular button surrounding the profileImageView.
-(void)showMenu:(UIGestureRecognizer*)gesture {
[profileImageView removeGestureRecognizer:gesture];
[profileImageView setUserInteractionEnabled:NO];
ConcentricRadius radius;
radius.externalRadius = 75;
radius.internalRadius = 45;
GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:#"radio.png"] highlightedImage:[UIImage imageNamed:#"radio_selected.png"] radius:radius] autorelease];
[circularMenu setTag:kCircularTagControllerCircularMenu];
[circularMenu setCenter:[profileImageView center]];
// Buttons' frames will be set up by the circularMenu
UIButton *button1 = [[[UIButton alloc] init] autorelease];
UIButton *button2 = [[[UIButton alloc] init] autorelease];
UIButton *button3 = [[[UIButton alloc] init] autorelease];
UIButton *button4 = [[[UIButton alloc] init] autorelease];
[circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];
//[[self view] addSubview:circularMenu];
[[self view] insertSubview:circularMenu belowSubview:profileImageView];
}
Now I handle manually the touchEvent inside the circularMenu using the touchMoved methods.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];
for (UIView *aSubview in _roundButtons) {
if ([aSubview isKindOfClass:[UIButton class]]) {
UIButton *aButton = (UIButton*)aSubview;
CGPoint buttonTouchPointConverted = [aButton convertPoint:touchLocation toView:aButton];
if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
[self rotateHighlightImage:aButton];
}
}
}
}
The goal is always to handle the end of gestureRecognizer and pass the touch event to the new instance created without having to lift my finger from the screen.
Any ideas?
PD: I handle touch manually with touchMoved cause if I use the addTarget:action:forControlEvents: on my buttons (1,2,3, and 4) the button that detect touchEvent swallow it and make other buttons impossible to feel the touch moving over them.
Your touchesEnded:withEvent: will have to be the same as your touchesMoved:withEvent: except it must invoke the method which is probably tied to the control event Touch Up Inside event.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [(UITouch*)[touches anyObject] locationInView:self];
for (UIView *aSubview in _roundButtons) {
if ([aSubview isKindOfClass:[UIButton class]]) {
UIButton *aButton = (UIButton*)aSubview;
CGPoint buttonTouchPointConverted = [aButton convertPoint:touchLocation toView:aButton];
if (CGRectContainsPoint([[aButton layer] frame], buttonTouchPointConverted)) {
[aButton sendActionsForControlEvents:UIControlEventTouchUpInside];
return;
}
}
}
}
The only change I have made is to have the button send that control event for us.
Original Answer
In the function that handles your gesture, do this,
if ( gesture.state == UIGestureRecognizerStateEnded ) {
CGPoint point = [gesture locationInView:button];
if ( CGRectContainsPoint(button.bounds, point) ) {
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
This checks whether the last touch of the gesture was inside the button and sends a touch up inside event to all its targets.
Ok guys finally I solved my problem and I reached my goal!!
I discovered what was the real problem.
Simply the GestureRecognizer handle touch Event until it's state is setted to UIGestureRecognizerStateEnded and for this reason the GestureRecognizer swallow touch events with no opportunity to send touch events to the rest of responder chain.
I read again the UIGestureRecognizer class reference and I found the property enabled.
To solve my problem the first thing I do when the gesture launch the target method is to set the gesture enabled to NO. In this way the gesture release immediately the touch control and the touchMoved can be executed.
Hope this help someone.
Above the modified code:
-(void)showMenu:(UIGestureRecognizer*)gesture {
[gesture setEnabled:NO]; // This is the key line of my problem!!
[profileImageView removeGestureRecognizer:gesture];
[profileImageView setUserInteractionEnabled:NO];
ConcentricRadius radius;
radius.externalRadius = 75;
radius.internalRadius = 45;
GTCircularButton *circularMenu = [[[GTCircularButton alloc] initWithImage:[UIImage imageNamed:#"radio.png"] highlightedImage:[UIImage imageNamed:#"radio_selected.png"] radius:radius] autorelease];
[circularMenu setTag:kCircularTagControllerCircularMenu];
[circularMenu setCenter:[profileImageView center]];
// Buttons' frames will be set up by the circularMenu
UIButton *button1 = [[[UIButton alloc] init] autorelease];
UIButton *button2 = [[[UIButton alloc] init] autorelease];
UIButton *button3 = [[[UIButton alloc] init] autorelease];
UIButton *button4 = [[[UIButton alloc] init] autorelease];
[circularMenu setButtons:[NSArray arrayWithObjects:button1, button2, button3, button4, nil]];
//[[self view] addSubview:circularMenu];
[[self view] insertSubview:circularMenu belowSubview:profileImageView];
}
I think you should change a setting on the view, once you create the button. Eg.
myImageView.userInteractionEnabled = NO;
This way, the UIImageView will not listen to the touches any more.
Let me know if it works.