I have to use swipe functionality in my view controller.
so, whenever Iam swiping, my swipe method is getting called twice and the NSlogs which I Wrote inside the (swipe:) method is displaying the content two times.
Here is the code which i have used.
UIView *swipeView=[[UIView alloc]initWithFrame:CGRectMake(405, 420, 265, 35)];
swipeView.backgroundColor=[UIColor clearColor];
[self.view addSubview:swipeView];
UISwipeGestureRecognizer *gesture;
gesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipe:)];
[gesture setDirection:(UISwipeGestureRecognizerDirectionRight)];
[swipeView addGestureRecognizer:gesture];
[gesture release];
[swipeView release];
-(void)swipe:(UISwipeGestureRecognizer *)recognizer {
NSLog(#"Swipe received.");
NSLog(#"HIJ");
}
please tell me what i have to do for calling it only one time.
That's what's supposed to happen. You need to look at the state property where you'll find things like UIGestureRecognizerStateBegan and UIGestureRecognizerStateEnded.
Try this, recognizer has various state like
UIGestureRecognizerStatePossible,
UIGestureRecognizerStateBegan,
UIGestureRecognizerStateChanged,
UIGestureRecognizerStateEnded,
UIGestureRecognizerStateCancelled,
UIGestureRecognizerStateFailed,
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
-(void)swipe:(UISwipeGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded) {
NSLog(#"Swipe received.");
NSLog(#"HIJ");
}
}
Related
I made gesture like this:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(tapOnPhoto:)];
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
tapGesture.delegate = self;
[self.htmlWebView addGestureRecognizer:tapGesture];
And when tap on htmlWebView call gestureRecognizerShouldBegin for several time.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){
[self performSelector:#selector(tapOnPhoto:) withObject:gestureRecognizer];
}
return YES;
}
Why is gestureRecognizerShouldBegin called more than once per gesture?
As per the
gestureRecognizerShouldBegin description.
This method is called when a gesture recognizer attempts to transition
out of the UIGestureRecognizerStatePossible state. Returning NO causes
the gesture recognizer to transition to the
UIGestureRecognizerStateFailed state.
This method will get called multiple times to get the transition state of gesture.
Also as you have added a selector for TapGesture why are you calling that method explicitly, the method will get called itself.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){
[self performSelector:#selector(tapOnPhoto:) withObject:gestureRecognizer];
}
return YES;
}
There will be no need of this function you can remove it as you are calling only a method there.
As #Rajat mentioned in his answer you can remove the delegate method and instead use your tapOnPhoto: method to parse your gesture logic.
The UIGestureRecognizer object that you'll receive as the argument into that method has a property called state
Which might have the following values:
UIGestureRecognizerStatePossible
UIGestureRecognizerStateBegan
UIGestureRecognizerStateChanged
UIGestureRecognizerStateEnded
UIGestureRecognizerStateCancelled
UIGestureRecognizerStateFailed
UIGestureRecognizerStateRecognized
You can use a switchand provide specific logic for each case.
I added a swipe gesture recognizer and a pan gesture recognizer to the same view. These gestures should be exclusive to each other.
In order to do this I added the constraint on the swipe gesture
[swipeGesture requireGestureToFail:panGesture];
(because the pan gesture should get precedence)
Problem is that the pan gesture is always invoked - even during a very fast swipe.
In order to over come this I set myself as the pan gesture's delegate. In the delegate method I set up some code as follows:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// check if it is the relevant view
if (gestureRecognizer.view == self.myViewWithTwoGestures)
{
// check that it is the pan gesture
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
{
UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint velocity = [pan velocityInView:gestureRecognizer.view];
// added an arbitrary velocity for failure
if (ABS(velocity.y) > 100)
{
// fail if the swipe was fast enough - this should allow the swipe gesture to be invoked
return NO;
}
}
}
return YES;
}
Is there a suggested velocity to ensure good behavior? Is there another way to force the pan gesture to fail?
According to Apple's documentation here (under Declaring a Specific Order for Two Gesture Recognizers) the way to get both UIPanGestureRecognizer and UISwipeGestureRecognizer to work on the same view is by requiring the UISwipeGesureRecognizer to fail before calling the UIPanGestureRecognizer (the opposite of what you wrote). This probably has something to do with the fact the a swipe gesture is also a pan gesture but the opposite is not necessarily true (see this SO question).
I wrote this little piece of code and it manages to recognize both pan and swipe gestures:
UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(panned:)];
UISwipeGestureRecognizer * swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swiped:)];
[pan requireGestureRecognizerToFail:swipe];
swipe.direction = (UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight);
-(void)panned:(UIPanGestureRecognizer *)gesture
{
NSLog(#"Pan");
}
-(void)swiped:(UISwipeGestureRecognizer *)gesture
{
NSLog(#"Swipe");
}
This doesn't work as well as you'd hope (since you need the swipe gesture to fail there's a small delay before the pan gesture starts) but it does work.
The code you posted however gives you the ability to fine tune the gestures to your liking.
Late response, but I was having a similar issue where I wanted to pan to be recognized before the swipe. The only way I could get it working was to use a long press (or something similar) to set a flag to use the pan gesture as a pan or a swipe. I ended up not using swipes at all. I.e.:
- (void) handleLongPress : (UILongPressGestureRecognizer *) gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
_canSwipe = YES;
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
{
_canSwipe = NO;
}
}
- (void) handleDragging : (id) sender
{
UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)sender;
GLKVector2 dragDelta = GLKVector2Make(0., 0.);
if (pan.state == UIGestureRecognizerStateBegan || pan.state == UIGestureRecognizerStateChanged)
{
_mousePosition = [pan translationInView:self.view];
if (_beginDragging == NO)
{
_beginDragging = YES;
}
else
{
dragDelta = GLKVector2Make(_mousePosition.x - _prevMousePosition.x, _mousePosition.y - _prevMousePosition.y);
}
_prevMousePosition = _mousePosition;
}
else
{
_beginDragging = NO;
}
if (_canSwipe == YES)
{
if (dragDelta.x > 0)
{
_canSwipe = NO;
[self.navigationController popToRootViewControllerAnimated:YES];
NSLog(#"swipe right");
}
else if (dragDelta.x < 0)
{
_canSwipe = NO;
[self performSegueWithIdentifier:#"toTableSegue" sender:pan];
NSLog(#"swipe left");
}
}
else
{
_dragDeltaTranslation = GLKVector2Make(dragDelta.x/90, dragDelta.y/90);
_translationXY = GLKVector2Make(_translationXY.x + _dragDeltaTranslation.x, _translationXY.y - _dragDeltaTranslation.y);
}
}
So essentially:
Use long press (or some other mechanism) to activate a state of swiping (long press is nice because as soon as you release, the state goes to UIGestureRecognizerStateEnded)
Then use the pan direction to determine the direction of the swipe.
2.
UITapGestureRecognizer *PressRecognizer1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handlePress:)];
[PressRecognizer1 setNumberOfTouchesRequired:1];
[firstBtn addGestureRecognizer:PressRecognizer1];
-(void)handlePress:(UITapGestureRecognizer*)PressRecognizer {
NSLog(#"working");
if (PressRecognizer.state == UIGestureRecognizerStateBegan) {
UIButton *whichButton=(UIButton *)[PressRecognizer view];
NSLog(#"whichButton %d\n",whichButton.tag);
if (whichButton.tag == 0) {
NSLog(#"currentImageId1 %d",currentImageId1);
[delegate imageZoom:currentImageId1];
}
I have created a UITabelView with customcell which has three images per row.When tap on a image hadlePress method called.But i does not come inside first if condition.
from apple docs:
Although taps are discrete gestures, they are discrete for each state of the gesture recognizer; thus the associated action message is sent when the gesture begins and is sent for each intermediate state until (and including) the ending state of the gesture. Code that handles tap gestures should therefore test for the state of the gesture, for example:
- (void)handleTap:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateEnded)
{
// handling code
}
}
if you NSLog(#"%d",sender.state) inside the method (before the if statement) you'll see that the method is getting fired only with the UIGestureRecognizerStateEnded state, thus you should change your
if (PressRecognizer.state == UIGestureRecognizerStateBegan)
to
if (PressRecognizer.state == UIGestureRecognizerStateEnded)
In my app I have this code:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)recognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UIScrollView class]]){
return YES;
}
else return NO;
}
In this I control if my touch is inside a scrollView or not but now I want to check if the touch is a simple touch or is a swipe gesture, is there a way to detect it?
thanks
The method you written above is UIGestureRecognizerDelegate. This is a delegate method will get called when particular gesture on which you put an observer, gets detected.
In order to identify swipe gesture, you have to add Gesture recognizer to View on which you want to detect as below:
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
You can get gesture detection in method handleSwipeForm:
If you want to get the above delegate to get called then also add this line,
recognizer.delegate = self;
Use UISwipeGestureRecognizer to detect swipe gestures (you can set the swipe direction: UISwipeGestureRecognizer.direction)
And a UITapGestureRecognizer to detect taps (UITapGestureRecognizer.numberOfTapsRequired sets the required number of taps to trigger the recognizer (e. g. for double-taps)
You have to use UISwipeGestureRecognizer in order to detect swipe gestures .
UISwipeGestureRecognizer *swipeGest= [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(SwipeRecognizer:)];
[swipeGest setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:swipeGest];
swipeGest.delegate = self;
setDirection is used to set the swipe detect direction.
- (void)SwipeRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
}
Here we will be writing the function to do after detecting the swipe gesture.
According to image could you please advise me which function use to develop this feature?
i'm not sure, is it implement from UIPopover?
any idea, thank you.
source from Music.app iOS 5 beta 2
You can use a UIGestureRecognizer. Specifically, what you are looking for is a UILongPressGestureRecognizer
You should instantiate one and attach it to the view you would like to track the gesture on:
UILongPressGestureRecognizer* gestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[view addGestureRecognizer:gestureRecognizer];
Then, in your handler method you would do the rest:
- (void)handleGesture:(UILongGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
}
}
EDIT: for the popover implementation, have a look at WEPopover