I'm using UILongPressGestureRecognizer to catch a Long Press event. The problem is I can only respond to it after user release his finger.
How do I implement a function that will respond after user hold for x seconds?
UILongPressGestureRecognizer works for this, check your code again and set duration for long press as -
[longPressGesture setMinimumPressDuration:<#(CFTimeInterval)#>];
Instead of using a gesture recognizer, use the UIView instance methods touchesBegan:withEvent:, touchesMoved:withEvent: and touchesEnded:withEvent:. While they're not as convenient as using a gesture recognizer, you have complete control of the touch interpretation.
Note that if you every try to use these to interpret multitouch gestures, the touch screen is "bouncy", in that the reported number of touches will vary during the touch event processing. My app interprets pinches, which are reported to me as a random sequence of one and two finger touches. I managed to debounce it, but getting the code right was a real PITA.
Related
I am successful in monitoring raw touches using GSEvent by hooking sendEvent. How do I extract touch information when multiple fingers are involved?
Update 1: iOS 5.01
Update 2: I managed to do this by going over the allTouches set contained in the event passed. It works fine, but bogs down a when gesture recognizers kick in for a 4 or 5 finger event..
You are kind of right. By overriding the sendEvent: method, and then getting the GSEvent from the UIEvent, you can get the underlying sytem information you are looking for. You could watch the "infoSize" field in the GSEvent record, which should tell you how many touches are involved in the event... But why use GSEvent? You could just put one big UIView in your application, set it's multiple touch interaction property as YES, override it's sendEvent method, and you should get every touch in there, even the 4 and 5 finger gestures. You can forward touches that are not important for you, and don't forward the ones that are not.
Hope this helps.
I am trying to have an image that when the user touches it, it wiggles and as soon as the user lifts their finger it stops.
Is there a gesture that I can use to detect when the finger is down, not just on the initial touch, or when the user moves there finger?
I have tried a LongPress gesture, but that does not get called the entire time the finger is on the view. Can anyone help me with the best way to active this. Right now i am doing it using touchesBegin, touchesMoved, touchesEnd, but i was wondering if there is a better way.
Any suggestions are greatly appreciated.
Thanks
EDIT
Based on the comments, I slightly misunderstood the original question, so I edit my answer to a different solution, which hopefully is a bit more clear (and answers the actual question - not the one that was in my head).
A LongPress gesture is continuous (where a tap gesture is not). That means, the recognizer callback will continue to be invoked until the gesture is complete - which does not happen until the "longpress" is released. So, the following should do what you want. NOTE: I think you want to "start shaking" a view when the long-press is recognized, then "stop shaking" the view when the fingers are released. I just pretended you have functions for that. Substitute appropriately.
- (void)handleLongPress:(UILongPressGestureRecognizer*)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
StartShakingView(gestureRecognizer.view);
} else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
StopShakingView(gestureRecognizer.view);
}
}
The Apple Touches sample includes code that demonstrate using both UIResponder and UIGestureRecognizer methods.
Either should work for what you're doing.
Simple answer - you could make the image a UIButton, and start the wiggle on TouchDown, and stop it on TouchUpInside or TouchUpOutside
It sounds like you want to subclass UIGestureRecognizer, which, as I recall, gets the touchesBegan:... and associated methods. Read the notes on subclassing in the UIGestureRecognizer reference. Or use a UIButton as SomaMan suggests.
I have an app that uses gesture recognizers quite a bit. From the studying I have done, I have found that there is the touchesBegan method of recognizing a gesture, and then there are gesture recognizers, which should be more slick.
The problem I am running into is that the gesture recognizers aren't nearly as responsive or accurate as the touchesBegan method, but are a lot easier to implement, which is obviously why I am using them. If I want to have a 3 finger gesture detected with a gesture recognizer, it is quite difficult because I have to press down my 3 fingers at the EXACT same time, or else it won't fire. This is in contrast to the touchesBegan method that just knows how many fingers you have down at any point.
Am I missing something with the implementation of this seemingly nice gesture feature that is making it not very responsive? I have set the max and min touches to 3, is that incorrect?
Please help. Thanks!!
The reason you need to press at the exact same time is because, by default, only one gesture recognizer can be recognized at a time. So once you press one finger down that recognizer automatically blocks the other two.
Try implementing the UIGestureRecognizerDelegate and using:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
I'm not sure if this will solve the issue or not but it might.
Cheers.
I am able to understand that when user just touches the view, touches Began and Ended called. When user swipes their hand on a view, touches Moved method gets called. But when does touches Cancelled get called or by what action on user this method gets called?
I think probably the most common reason for touchesCancelled being called (since iOS 3.2 anyway) is following the recognition of a gesture by a UIGestureRecognizer. If your view has any kind of gesture recognizer attached to it then it is often very important to provide a custom implementation of the touchesCancelled method - note this includes ready made views that use gesture recognizers, including UIScrollView.
By default, gesture recognizers cancel the delivery of touches to the hit-test view upon recognition, although this behaviour can be disabled. This involves sending the touchesCancelled message to that view, most likely following a touchesBegan or touchesMoved message. If your touch handling code is relying on code implemented in the touchesEnded method, it is possible this may never be fired and some kind of serious problem could occur, hence the need to properly tie up any loose ends in touchesCancelled.
The ins and outs of gesture recognizer functionality is obviously a bit more complex than I've mentioned here - I would thoroughly recommend reading Apple's Gesture Recognizers documentation.
Also, check out the WWDC videos on gesture recognizers (starting from 2010).
Note: touches also get cancelled if you start a UIView animation after touchesBegan. To prevent this make sure you include UIViewAnimationOptionAllowUserInteraction:
e.g.
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
self.aView.hidden = NO;
self.aView.alpha = 1;
} completion:nil];
From the Apple Reference documents
Sent to the receiver when a system
event (such as a low-memory warning)
cancels a touch event.
Discussion
This method is invoked when the Cocoa
Touch framework receives a system
interruption requiring cancellation of
the touch event; for this, it
generates a UITouch object with a
phase of UITouchPhaseCancel. The
interruption is something that might
cause the application to be no longer
active or the view to be removed from
the window
When an object receives a
touchesCancelled:withEvent: message it
should clean up any state information
that was established in its
touchesBegan:withEvent:
implementation.
The default implementation of this
method does nothing. However immediate
UIKit subclasses of UIResponder,
particularly UIView, forward the
message up the responder chain.
And, from the Event Handling Guide for iOS, p. 19:
It sends the touchesCancelled:withEvent: message when the touch sequence is cancelled by a system event, such as an incoming phone call.
I was handling touchesBegan()/touchesMoved() on a view under UIScrollView, which is challenging. My touches kept cancelled by somewhere when I pinch (somehow it is OK with single touch movement), I was investigating how to stop being cancelled. I figured out, that there is a property Can Cancel On Scroll on UIScrollView, and you may check it off to stop being cancelled, if your case is similar to my case.
It sounds there are many cases where your touches are being cancelled, so my answer is just one of them.
I was trying to implement palm rejection functionality for a drawing app i developed for iPhone and noticed some weird behavior in touch events. When i place my palm on the screen and continuously lift some region of my hand up and then lower it down again, i get lots of touchBegin events but only a few touchEnd events. Is there something i don't know about the touch handling mechanism of iOS? Shouldn't be the number of touchEnd and touchBegin events belonging to each UITouch object equal?
There is only one view on my window and it occupies the entire screen. Both the view and the window have multitouch enabled. I'm counting the events by printing the number of touches using NSLog's at the beginning of touchBegin and touchEnd methods. So i'm taking into account the fact that a single event may contain info about multiple touches.
Don't forget to provide a handler for touchesCancelled events. You can get a touchesCancelled call after a touchesBegan and without a matching touchesEnded event.
Rather than looking at the number of touchesBegan:withEvent: and touchesEnded:withEvent: calls, you should look at the NSSet of UITouch objects passed to those methods. So, for example, if you placed one finger then a second finger on the screen, you'd get two touchesBegan:withEvent: calls. If you lifted both fingers from the screen simultaneously, you'd get a single touchesEnded:withEvent: call; the NSSet of UITouch objects passed in would indicate that two fingers were lifted.