TouchesMoved stops firing for no reason - ios

I added a custom gesture recognizer to a ViewController's view. Once a touch starts, the custom class reports the touch.force in NSLog every time the touchesMoved function fires off.
If you start touching and the move your finger even just a few millimeters, then the touchesMoved events will fire off continually until you lift up your finger and the touchesEnded event fires.
However if you start touching and DON'T move your finger at all, then the touchesMoved events will only fire off a few times, maybe 10-20 times, and then they just stop. After that, the touchesCancelled function does not get called and neither does touchesEnded.
Why is this happening? I want it to keep firing touchesMoved forever until the finger is lifted up.
I saw this other similar question here: iOS app stops responding to touch events until I move my finger on/off screen
But there is no answer to that one either.

Related

touchesEnded not getting called after device changes orientation

I am implementing touchesBegan and touchesEnded in my iOS application trying to detect when the user puts a finger on the screen and when he releases it.
The problem I am having is that as soon as touchesBegan gets called, if the user rotates the device while still holding his finger on the screen, when he lets go of the screen, touchesEnded does not get called.
Does anyone know why this might be happening?
Are you getting touchesCancelled instead?
In general, the system will call either touchesEnded or touchesCancelled after a touchesBegan, so code should deal with both. Touches can be cancelled for various reasons, such as a gesture recognizer taking over, an non-interactive animation starting on the view, an incoming phone call, etc.

How to get a method called after all multitouch events in render loop are fired?

I am creating a multitouch iOS toy where user slides fingers over the screens and triggers various animations when passing over 'widgets'.
I have empty spaces between widgets, but I want every touch to make something happen. Therefore I catch touches in a root UIView, and find closest widget for each touch, instead of using each widget's touch handlers (which only work within it's frame).
To do that, I listen on touchesBegan, touchesMoved, touchesEnded and touchesCancelled, and find closest widget for each touch. Then this widget keeps touches assigned to it, and an animation plays when that count changes from 0 (= at least one finger is in an area closest to object) or back to 0 (all fingers left).
My problem is, that when for example a finger drags out of widget's area in touchesMoved (= touchCount--) while another finger is just placed there in touchesBegan (= touchCount++), two animatons (leave and enter) get triggered, even though the final state is that there was 1 finger before this render loop and there is 1 finger at the end, so nothing should happen.
For this though, I would need some event to fire during every render loop after all multitouch handlers are called, so that I could keep a previous and current touchCount for each widget, and fire animation only for widgets where touchCount changed.
Is there a way to get such a method call? Or, could I expect that for example if I get a method called in every render loop, that all touches* methods for this frame were already called?
Thanks!

Avoid triggering touchesBegan: until a swipe gesture recognizer fails

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...

touchesEnded or touchesCancelled not always called

This issue I think deserves its own question. Using the code attached to my solution to another problem I discovered the issue described here.
I have the main view controller set as a UIGestureRecognizerDelegate, and I implement touchesBegan, touchesMoved, touchesEnded, and touchesCancelled programming my solution with the assumption that for every touch object with a touchesBegan event there would be a touchesEnded or touchesCancelled event for that same object. I'm finding that not to be the case, though.
Scenario:
The following events happen in this order.
User starts gesture 1, touching the screen and sliding the finger.
User starts gesture 2, touching the screen at a different location.
User continues to slide both fingers at their respective parts of the screen.
User lifts finger off the screen for gesture 2.
User continues gesture 1.
User lifts finger off the screen for gesture 1.
Using NSLog to capture the details of the touch event, I find that a separate touch object is used for gesture 1 and gesture 2. But while touchesBegan, touchesMoved, and touchesEnded are all called for gesture 1, only touchesBegan and touchesMoved are called for gesture 2. The event touchesCancelled is not called for it either.
So how can I tell when gesture 2 finishes if touchesEnded and touchesCancelled are not called?
Edit: I found another post with similar symptoms. Most of my subviews are created programmatically, though. I'll try what was suggested there for the others. I'm skeptical it is the same issue, though, since in my testing, the touch locations are not anywhere near the other views.
Another edit: Following the recommendation in the link posted in my previous edit, I looked at the subviews, and one had user interaction checked. After I unchecked it, the behavior is slightly different. Now the second touch isn't noted at all in any of the touch events. I must be missing something basic. The main view, and the view with user interaction checked, by the way, both occupy the same space (one encapsulates the other).
My original assumption that each touch would have its own object that starts at touchesBegan and ends with either touchesEnded or touchesCancelled I think is correct. It is with my current implementation anyway. I originally wasn't seeing a second touch because Multiple Touch was not enabled for the view I was working with. I enabled that, per suggestion in the comments. After that, I was able to see some, but not all touch events for the second touch. The reason I was sometimes not seeing the second touch was because I had a subview that had user interaction enabled. Apparently, it was commandeering the touches. I unchecked that and then was able to see the touch objects.
I then switched tracking the touches by coordinates to touch IDs and was able to track the complete lifespan of all touches. Tracking by coordinates didn't work because I found that for the second touch, the touchesEnded coordinates were identical to the last one in touchesMoved rather than the previous location in touchesEnded matching the touchLocation in touchesMoved as with the first touch. If this sounds confusing, just track the touches by touch ID instead of by coordinates.
How about you put something like this in your touchesMoved method
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray* touchData = #[touches,event];
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self
selector:#selector(touchesFinishedWithoutCallback:) userInfo:touchData
repeats:NO];
[self.timer fire];
}
The touchesFinishedWithoutCallback: method will only get called when touchesMoved stops getting called.
Needs elaborating for multiple touch, but could be a solution?

Touch Events touchesCancelled and touchesEnded

I have a project that I started out using a tap gesture recognizer for. I realized I didn't have enough control with the tap gesture recognizer, so I've started coding with using my viewcontroller as a UIGestureRecognizerDelegate. Just to make sure I was on the right track, I added methods for touchesBegan, touchesMoved, touchesEnded, touchesCancelled. The methods are empty except for NSLog calls so I can tell what is being fired when I try different things.
Things worked as expected except that I was getting a bunch of calls to touchesCancelled. I assume this is because of the tap gesture recognizer I still have in place. I'm not ready to remove the tap gesture recognizer, so I just wanted to confirm that this is what would happen if a gesture I used was actually a tap.
The documentation says:
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.
But I suspect my scenario just outlined is just as likely. Am I correct?

Resources