If you start pressing the screen, but move the finger because minimumPressDuration ellapses, the gesture gets cancelled and your movement gets forwared to the view. If minimumPressDuration is reached, it doesn't matter how much you move the finger. I want to avoid this and always cancel my gesture if the finger movement is bigger than allowableMovement.
I've seen this thread, but that solution isn't working for me.
I've tried subclassing UILongPressureGestureRecognizer, and set the state to failed or cancelled when my requirement is met, but doesn't seem to work, I guess cancelling it isn't enough and have to forward the events myself? How should I do this? My intention is to use it together with MKMapView. I'm getting really frustrated with this, I've tried it for two days.
Try this one :
UILongPressGestureRecognizer *longpress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(LongPress_action:)];
longpress.minimumPressDuration = 2.0; //seconds
longpress.delegate = self;
[yourview addGestureRecognizer:longpress]; // where you want to add
Call this method :
- (void)LongPress_action:(UILongPressGestureRecognizer*)gesture
{
if ( gesture.state == UIGestureRecognizerStateEnded )
{
NSLog(#"Long Press");
}
}
Related
I need to animate view translation from A to B on the screen.
However, I want that translation to occur when a user swipes his thumb on the screen.
I also want translation to depend on the thumb swipe in a way that they follow one another.
I assume I will need some sort of listener, which will follow my thumb motion on the screen and I would somehow tell my view to move on the screen left or right, depending on the direction of the swipe.
How can I achieve that?
I would use the UIPanGestureRecognizer, because it has more control, for example if you move slow, it can still pickup where your movement is, then maybe you can position your translation accordingly.
You can do something like:
var panRecongniser = UIPanGestureRecognizer(target: self, action: Selector("didPanRecongnised:"))
in your viewDidLoad, and then:
func didPanRecongnised(recongniser: UIPanGestureRecognizer){
if(recongniser.state == UIGestureRecognizerState.Changed || recongniser.state == UIGestureRecognizerState.Began){
self.didPanMove(recongniser)
}else if(recongniser.state == UIGestureRecognizerState.Ended || recongniser.state == UIGestureRecognizerState.Cancelled){
self.didPanEnd(recongniser)
}
}
and in your didPanMove:
func didPanMove(recongniser: UIPanGestureRecognizer){
if((self.view.superview) != nil){
if(recongniser.state == UIGestureRecognizerState.Began){
// save the original position
self._origPoint = self.view.frame.origin
}
// this is the translation of the last segment of the "move"
let trans = recongniser.translationInView(self.view.superview!)
// this is the velocity of the last segment of the "move"
let velocity = recongniser.velocityInView(self.view.superview!)
}
}
Use the translation values to workout which direction the user is swiping. Don't forget to add the "trans" value as the accumulated translation each time "didPanMove" is called.
You can now use those value to do a number of things. Like having the appearing view to follow the progress of your finger. Or when the velocity reaches certain speed, having the view "snap" to the required position, like with a swipe. And maybe if the user don't swipe fast enough or far enough, having the view follow the finger a bit, then "snap" back to the hiding position when the gesture ends.
To do the animation, if you're doing a custom sliding out view, you can probably use UIView.animateWithDuration to animate your view sliding out.
I hope it helps you...
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(tappedRightButton:)];
[swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.view addGestureRecognizer:swipeLeft];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(tappedLeftButton:)];
[swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
[self.view addGestureRecognizer:swipeRight];
So I was just trying to make a replica of flappy bird. But, I was wondering how to achieve a bird flap? I thought of using the method
- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
but I noticed that if you use this method and press down on the screen, the bird will flap continuously. I just want the bird to flap when I tap the screen, and if I press down on the screen it will behave the same way as tapping once.
Is there a class reference that utilizes these sort of action?
For getting the tap event, you can use the UITapGestureRecognizer provided by Apple.
Simply initiate it, set the parameters according to your requirements and add it to the view you want to record the tap.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
tap.numberOfTapsRequired = 1;
tap.numberOfTouchesRequired = 1;
[demoView addGestureRecognizer:tap]; // The gesture recognizer is being added to demoView
[tap release]; // In case of not using ARC
And the define the selector which you mentioned in the initialization.
- (void)handleTap:(UITapGestureRecognizer *)recognizer{
// Handle the tapping here
}
I´m very frustrated because I can´t draw the Ground like in Flappy Bird... I try to use this method:
private void drawGround(){
for(Rectangle mRectangleGroundHelper : mArrayGround){
if(spawnGround & mRectangleGroundHelper.x<0){ // spawn Ground if the actual ground.x + ground.width() is smaller then the display width.
mArrayGround.add(mRectangleGroundHelper);
spawnGround = false;
}
}
for(Rectangle mRectangleGroundHelper : mArrayGround){
if(mRectangleGroundHelper.x < -mTextureGround.getWidth()){ // set boolean to true, if the actual ground.x completely hide from display, so a new ground can be spawn
spawnGround = true;
}
}
for(Rectangle mRectangleGroundHelper : mArrayGround){ // move the ground in negative x position and draw him...
mRectangleGroundHelper.x-=2;
mStage.getSpriteBatch().draw(mTextureGround, mRectangleGroundHelper.x, mRectangleGroundHelper.y);
}
}
You can download app at here
Throughout iOS 7 there's many situations where users can slide their finger in from the left or right edge of the screen in order to perform an action, such as popping a view controller or showing a sidebar.
Is there a built in way to do this that I've completely overlooked somehow (yes, I've searched extensively)? Or is the only way to check the frame position of where the pan started?
This is because I want to perform distinct actions if the user pulls from the edge, or say the middle.
You have UIScreenEdgePanGestureRecognizer, which is added to iOS7 to detect, well, panning from the edges of the screen. For panning from the middle, a normal pan gesture recognizer will suffice, where you can check if the pan gesture originated close enough to the middle.
Use the UIScreenEdgePanGestureRecognizer, but check that it's available first (since it's iOS 7+):
if (NSClassFromString(#"UIScreenEdgePanGestureRecognizer")) {
UIScreenEdgePanGestureRecognizer *panRecognizer =
[[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self
action:#selector(handleScreenEdgePanGesture:)];
panRecognizer.edges = UIRectEdgeLeft;
}
Set up gestures
UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanning:)];
[self.view addGestureRecognizer:panGesture];
Handling gesture states
- (void)handlePanning:(UIPanGestureRecognizer *)gestureRecognizer
{
switch ([gestureRecognizer state])
{
case UIGestureRecognizerStateBegan:
[self startDragging:gestureRecognizer];
break;
//u won't need following cases
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed:
[self stopDragging:gestureRecognizer];
break;
default:
break;
}
}
Recognizing start point of drag
- (void)startDragging:(UIPanGestureRecognizer *)gestureRecognizer
{
CGPoint pointInSrc = [gestureRecognizer locationInView:yourVIEW];
}
The pan gesture recognizer is a predefined recognizer, about all you can do with it is to determine how fast the user moved their finger. If you want to tell if where the movement started, you'll have to code your own recognizer. It's not that difficult, you'll be notified when the touch started and where it ended.
I've been experimenting with UIGestureRecognizers and the new SKScene/SKNode's in SpriteKit. I've had one problem, and I got close to fixing it but I am confused on one thing. Essentially, I have a pan gesture recognizer that allows the user to drag a sprite on the screen.
The single problem I have is that it takes ONE tap to actually initialize the pan gesture, and then only on the SECOND tap on it works correctly. I'm thinking that this is because my pan gesture is initialized in touchesBegan. However, I don't know where else to put it since initializing it in the SKScene's initWithSize method stopped the gesture recognizer from actually working.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.pan) {
self.pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(dragPlayer:)];
self.pan.minimumNumberOfTouches = 1;
self.pan.delegate = self;
[self.view addGestureRecognizer:self.pan];
}
}
-(void)dragPlayer: (UIPanGestureRecognizer *)gesture {
CGPoint trans = [gesture translationInView:self.view];
SKAction *moveAction = [SKAction moveByX:trans.x y:-trans.y duration:0];
[self.player runAction:move];
[gesture setTranslation:CGPointMake(0, 0) inView:self.view];
}
That's because you're adding the gesture in touches began, so the gesture doesn't exist until the screen has been tapped at least once. Additionally, I would verify that you're actually using initWithSize: as your initializer, because you shouldn't have any problems adding the gesture there.
Another option is to move the code to add the gesture into -[SKScene didMovetoView:] which gets called immediately after the scene has been presented. More info in the docs.
- (void)didMoveToView:(SKView *)view
{
[super didMoveToView:view];
// add gesture here!
}
This is my first post! Hoping to not trip over my own toes...
Hi guys, so I was having an issue with a UISwipeGestureRecognizer not working. I was initializing it in my initWithSize method so based on this post I moved it to my didMoveToView method. Now it works (thanks 0x7fffffff). All I did was cut the following two lines from one method and paste them in the other.
_warpGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(warpToNextLevel:)];
[self.view addGestureRecognizer:_warpGesture];
In my "investigation" I came across userInteractionEnabled and tried to set it to YES in my initWithSize method...
self.view.userInteractionEnabled = YES;
NSLog(#"User interaction enabled %s", self.view.userInteractionEnabled ? "Yes" : "No");
This would log NO even though i'd just set it to YES. Further investigation found that if I don't try to manually set userInteractionEnabled then it's NO during initWithSize (I can't seem to change this if I want to) and automatically gets set to YES when i'm in didMoveToView.
This all strikes me as relevant but I would love for someone in the know to explain just what's going on here. Thanks!
In my app I have added the new Gesture Recognizers that are available in the 3.2 SDK. Everything appears to be working correctly and the response time on the screen been very fast. But for some reason when I add requireGestureRecognizerToFail to some of my gestures, there is a very visible delay when the gesture is triggered. Below is a snippet of the code that I use to create the Gesture Recognizers. Does anyone know why there is a delay and how I can fix it? I'm using requireGestureRecognizerToFail to prevent the SingleTap gesture from triggering when the user performs a DoubleTap.
- (void)createGestureRecognizers {
//Single Finger Double-Tap
UITapGestureRecognizer *singleFingerDTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSingleDoubleTap:)];
singleFingerDTap.numberOfTapsRequired = 2;
[super addGestureRecognizer:singleFingerDTap];
//Single Finger Tap
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSingleTap:)];
singleFingerTap.numberOfTapsRequired = 1;
[singleFingerTap requireGestureRecognizerToFail:singleFingerDTap];
[self addGestureRecognizer:singleFingerTap];
//Two Finger Pan
UIPanGestureRecognizer *panGesture2 = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePanGesture2:)];
panGesture2.maximumNumberOfTouches = 2;
[super addGestureRecognizer:panGesture2];
//Single Finger Pan
UIPanGestureRecognizer *panGesture1 = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePanGesture1:)];
panGesture1.maximumNumberOfTouches = 1;
[panGesture1 requireGestureRecognizerToFail:panGesture2];
[super addGestureRecognizer:panGesture1];
[singleFingerDTap release];
[singleFingerTap release];
[panGesture1 release];
[panGesture2 release];
}
If you want to distinguish between a single and double tap, you must wait long enough to figure out that no second tap is coming before you can call it a single tap. The alternative would be to design all your single tap actions in such a way that they can asynchronously be canceled or reverted when a double tap is detected.
For example, if you have a single tap change pages and a double tap zoom, then you would have to animate a page changing on single tap, then reverse the animation and zoom instead when a second tap is detected. By then the view that handled the single tap may have moved. In most cases, that is more trouble and confusion then it is worth.