I'm making a game on the iPad where the player swipes up, down, left, or right to move the character. An attack is controlled by touchesBegan:withEvent:
My problem is that the character attacks whenever he moves.
Is there a way to set up a swipe gesture so the code doesn't run touchesBegan:withEvent: until it sees if the motion is the beginning of a swipe or not?
This is not too easy of a task. Without using some custom gestures I would suggest you to try the combination of UISwipeGestureRecognizer and UILongPressGestureRecognizer. I know this sound silly but it is not: An UILongPressGestureRecognizer acts pretty much the same as the pan gesture so even if the finger is dragged you will receive events. You need to set some proper minimum duration till it fires (depends on the swipe gesture) and some large minimum drag length so it doesn't get canceled for dragging. You need to remove the touch event methods then and move the code to long press gesture action.
To explain the result, your long press gesture will (if set correctly) work just the same as touch events except it will wait for specified duration. If in that duration a swipe is detected your long press gesture will not fire. Seems just what you need...
Related
My app uses a paged horizontal scroll view. Each page has UIControls which the user can tap.
UIScrollView does a good job of handling cancellation of touches and swipes. If the user starts swiping fast enough, it's always a swipe. If the user touches down long enough to activate the highlighted state, the scroll view doesn't attempt to swipe.
I'm trying to duplicate this behavior with a UIPanGestureRecognizer subclass so that I can respond to downward swipes within my scrollview. However, I can't get the gesture to cancel in the event of the UIControls getting highlighted.
So far I've done the following:
self.refreshGesture.cancelsTouchesInView = YES;
self.refreshGesture.delaysTouchesBegan = NO;
self.refreshGesture.delaysTouchesEnded = NO;
This seems to duplicate the way UIScrollView passes touches to views, but it doesn't duplicate the way that UIScrollView's pan gesture recognizer gets cancelled. self.refreshGesture is always triggered no matter how slowly the user swipes, or what the state of the UIControls are.
I've tried setting the delegate on my gesture, and this may be the way to go. But I haven't found a combination that works. For example, just checking if the touch starts within a UIControl cancels too frequently. I've also tried overriding gestureRecognizerShouldBegin in my controls, but this seems like a hack and has far reaching implications (interferes with UITextView's gestures, for example).
In this GIF, you can see that the control activates on touch, and the scrollview cancels scroll if that happens. But my downward pan gesture is not cancelled in the same manner:
I wasn't able to duplicate this exactly, but there are two possibilities suggested by WWDC 2014 #235.
Add a transparent scrollview over your main content and move its gesture recognizer onto your root view. This is what did. It let me use UIScrollViewDelegate which ended up being sufficient.
Use a "timeout" gesture recognizer. The video suggests requiring the timeout gesture to fail, but in my case it worked better to use a long press gesture and cancel my pan if the long press fired. 0.1 seconds seemed to work better than their suggested 0.15 seconds.
I am using a UIPanGestureRecogniser to implement drag and drop. When the drag starts I need to identify the object that is being dragged. However the objects are relatively small. And if the user doesn't hit the object right in the centre of the object it isn't getting dragged.
The problem is that when the gesture handler is first called with the state UIGestureRecognizerStateBegan, the finger has already moved several pixels, and so [UIPanGestureRecognizer locationInView:] returns that point, which is not where the gesture truly started. That makes sense as it can only recognize a pan after a few pixels of movement. However, I need the absolute start of the gesture, not the position after the gesture has first been recognized.
I'm thinking that maybe I need to implement a tap gesture recognizer as well, purely to capture the first touch. But that seems like a hack for what is not an unusual requirement. Is there no other way of getting that first touch from within the pan gesture recognizer?
UIGestureRecognizerDelegate protocol provides methods gestureRecognizerShouldBegin: and gestureRecognizer:shouldReceiveTouch: that can help you evaluate the touches before the pan has transitioned to state UIPanGestureRecognizerStateBegan
I'm using a UIGestureRecognizer to recognize a single tap, a double tap and a longpress.
What I would like to do is also recognize a longpress, then swipe to either left or right.
Would this be possible given that I'm already consuming a longpress? I'm confused on this one and would appreciate pointers on how to do.
Thanks
Just tried this out myself and it seems as if the UILongPressGestureRecognizer will transition to its end state as soon as the UISwipeGestureRecognizer begins. Just make sure shouldRecognizeSimultaneouslyWithGestureRecognizer: returns YES for this gesture combination.
You'd need to use two gesture recognisers and make sure you track the state of the long press one when you receive a callback to say it's ended, and then do something based on the swipe/pan gesture following it.
I working with UIGestureRecognizer atm creating some map alike program.
My work require me to listen to both long press gesture and pan gesture separate, so each of them can do their own task.
But in one case, i need to listen to long press first to know which object is chosen. After that, when i begin to move my finger (without lift it up), that object will be move too. It kind of like drag a marker around in google map. But because my long press recognizer already fired, pan gesture recognizer didn't get fire until i tab on the screen again.
I tried something like
recognizer.enabled = NO;
recignizer.enabled = YES;
But it didn't help at all.
So i wonder if there anyway to cancel long press after it recognized (UIGestureRecognizerStateBegan) so pan gesture recognizer will be fire immediately when i begin to move. Or i have to use UIResponder to make it work ?
Thank for your advice.
You can actually use UILongPressGestureRecognizer to detect the pan gesture after the long tap. The only caveat is that, since UILongPressGestureRecognizer is a subclass of UIGestureRecognizer it does not have the -translationInView: that is so handy in UIPanGestureRecognizer.
You can anyway do these calculations on your own by keeping track of where the touch has moved after the long press, as it will keep firing the action bound to the gesture recognizer.
Take a look at this question, it may help to calculate the translation with the long press gesture.
I need to capture the following touch events on iOS and interpret them:
Finger A touch down within a UIButton (stays down)
Finger B performs a pan gesture elsewhere on the screen, providing continuous callbacks. (I plan to use a UIPanGestureRecognizer to implement this functionality).
Finger A touch up within the same UIButton
In essence, pressing and holding the UIButton puts the app into a special mode which lasts only as long as the button is held. Pan gestures performed during this time do different things to when the button is not pressed.
What I've tried so far:
hooking up the UIButton Touch Down and Touch Up Inside to IBActions in my UIViewController subclass. I've also
Problem encountered: the Touch Up Inside action is not called when another gesture happens on the screen from another finger while the button is pressed. This is because the original touch is cancelled.
attaching a UITapGestureRecognizer to the UIButton
Problem encountered: This only fires when the finger leaves the screen, hence it cannot be used to put the app into a special mode while the button is pressed.
I need to use a UIButton rather than a UIView so that the button has correct highlighting behaviour when pressed.
What is the best overall approach, given the problems I've encountered so far?
Use UILongPressGestureRecognizer with short minimumPressDuration on the "button"
http://developer.apple.com/library/ios/#documentation/uikit/reference/UILongPressGestureRecognizer_Class/Reference/Reference.html#//apple_ref/occ/cl/UILongPressGestureRecognizer
Important thing is to use gesture recognizer delegate to make sure that gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: returns YES for these recognizers. Then, when your UIPanGestureRecognizer calls the event handler, you can check the state of your UILongPressGestureRecognizer and if the button isn't pressed just ignore the pan gesture.