Objective-C: Get the UITouch for which the UIEvent was triggered - objective-c

I can't find anywhere in the documentation. When this message is called on my subclass of UIView:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
How can I get the touch for which this message was called ?
On both the NSSet and UIEvent I can get only sets of touches, but no unique identifier so I can determine which touch triggered the message.
PS: why on hell would they send a NSSet of all touches, and also the possibility to get the same set from [[event allTouches] anyObject]

You can't get the touch, because sometimes multiple touches triggered the message. If the user has two fingers on the screen, and moves both, you can get a single touchesMoved:withEvent: in which both touches are updated.
You need to process every touch in the touches set. If you've disabled multitouch for the view, so that you know there will only ever be one touch in the set, you can use touches.anyObject to get the touch. But if you haven't disabled multitouch, you need to loop over all of the touches in the set.
The message includes a set of touches separate from event.allTouches because the user might have three fingers down but only move one or two of them. The touches set only contains the moved touches, but event.allTouches contains all of the user's touches, including the touches that have not moved since the last message.
The unique identifier for the touch is the UITouch object itself. When the user puts a finger on the screen, iOS creates a UITouch object. It updates that object as the user moves his finger. So you can use the UITouch object as the key in an NSDictionary, or you can attach your own objects to it using objc_setAssociatedObject.

Related

Detecting all touches in an app

In an iPad app, wherever a user is touching the screen I want to display an image, highlighting the points they are touching. The app contains a number of nested views, all of which should receive touches and behave normally.
Seems simple, but I've failed to find a good way to do it. Using the touches began: with event and related functions on the root view controller does not work because if a subview is touched the events are not fired. I've also created a 'dummy' gesture recognizer which just passes touch events to another class which draws images. That works great-ish and buttons work, but breaks UIScrollViews and I'm guessing other subviews with gesture reconizers.
Is there nowhere you can just access all touch events without affecting where those touches are headed?
thanks.
Your dummy gesture recognizer should be ok. Just watch out for setting states. possible -> began -> ...
Basically your gesture recognizer is forwarding all touches so it can be in began or possible state all the time while any touch exists.
To get rid of problems with other gesture recognizers return YES in this delegate method.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Other option is to subclass main UIWindow in your app and override this method
- (void)sendEvent:(UIEvent *)event
Here you should have access to all events. It's quite easy to filter them.
You can apply a UITapGestureRecognizer to the entire view and set the cancelsTouchesInView property to NO. This will allow you to be notified of all taps on the view and its subviews without intercepting all of the touch events.
Additionally, you can implement the -gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: delegate method to keep this gesture recognizer from stomping on the ones used by views like UIScrollView.
you can try overriding hitTest:withEvent:
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
This maybe what you are looking for.

&& [[event allTouches] count] > 1

I have a UIButton whose MultipleTouchEnabled is NO. Still when I drag two fingers across it, the UIEvent I get has 2 UITouches in its allTouches property.
I want to only respond to dragging a finger around my button and ignore the second touch. If I use [[event allTouches] anyObject], I get (obviously) a random touch each time, and instead of a smooth drag across the screen my drag jumps around wildly.
My initial thought is that somehow I am still enabling multitouch, but I find no confirmation for this theory.

Conflicts between UIGestureRecognizer and in iPhone

I'm working in small app for iPhone which uses openGL.
The app is supposed to :
Move around the screen with a moving touch.
Zoom in/Out by tapping
I'm overwriting this functions to handle the coordinates of the touches and move around the screen with my finger, with success, working perfectly:
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
I'm using UIGesture recognizers to double taps, pinch gestures, swipes, counter pinch with success as well, all gestures being detected perfectly.
But I'm having conflicts. Some times for example, I do a double tap and it's recognized correctly, but it's also passed to my touchedMoved function, resulting in erratic movements. Same thing happens with pinch and counter pinch gestures, most of the time they work well in zooming in and out, but some times my touchesMoved function detect the touches as well and moves the screen.
It's a bad practice to overwrite this functions and use UIGesturerecognizer at the same time ?. If not, it's there a way to work with both without conflicts ?
I tried setting setDelaysTouchesBegan and setDelaysTouchesEnded to Yes in my recognizers, but this results in my touches not being passed to none of my overwritten functions!
I was thinking in using UIGestureRecognizer to handle swipes and scrap the overwritten functions to receive touches, and use the value of the swipe to calculate how much move my screen, is it possible ?
I can't answer for why you sometimes receive spurious touchesMoved: events, but it does sound like you may want to just ditch the overwritten functions and use a UIPanGestureRecognizer to handle moving around the screen.

Intercept UITableView scroll touches

Is it possible to control when the UITableView scrolls in my own code.
I am trying to get behaviour where a vertical swipe scrolls and a horizontal swipe gets passed through to my code (of which there are many example)
BUT
I want a DIAGONAL swipe to do nothing, i.e the UITableView should not even begin scrolling.
I tried catching it in here
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
but the scrollView.contentOffset.x is always 0 so I cannot detect a horizontal movement.
I also tried subclassing UITableView and implementing
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
etc..
but the UITableView (and I guess it's parent UIScrollView) start to scroll before the touches are notified?
To re-iterate, I want the UITableView scrolling to be locked if a diagonal swipe is made, but to scroll vertically normally.
(This behaviour can be seen in Tweetie(Twitter) for the iPhone)
Thanks for any help!
If you can work with 3.2 or later, the UIGestureRecognizer suite should allow this. There are a series of calls allowing some gestures to cancel or interoperate with other gestures, and you should be able to create a custom diagonal swipe gesture that cancels other gestures but does not actually do anything itself.
Prior to 3.2 the UIScrollView gesture handling is essentially undocumented. You can detect taps but not movements through the standard touchesBegan UIResponder calls. I think that once it detects movement it commandeers the run loop and captures all events, bypassing the normal event chain.
Note that setContentOffset is always called. You can create a subclass of UIScrollView and when you detect a diagonal shift during event tracking do not pass it to super. I do not know if, or how well this would work but it is somewhere to start.

multiple touch problem in Cocoa touch/i-phone

I am going to develop a ball game where i have to touch two/more
ball simultaneously.So how will i detect these multiple touch.
I came to know the following way i can detect multiple touch-
-(void)touchesBegan:(NSSet*)toucheswithEvent:(UIEvent*)event
{
UITouch* touch = [touches anyObject];
NSSet *touch2 = [event allTouches];
[touch2 count] //which count no. of touches
}
which detect only no. of touch. But I need to find out the (x-co-ordinate,y-co-ordinate) of these touch point.Not only this when i throw (means touch inside a ball and then slide the cursor) these ball how will i identify which ball is moving(means touchmove will identify which touchbegan??and if for each ball touchmove is called then how will i reset ball position because i gettting two touchposition(x1.x2) and (x2,y2) for 2 ball,so how will i say which ball belongs to (x1,y2) or (x2,y2)) .
In your code about touch2 is a set of UITouch objects
You can get at each object like so:
UITouch *touch = [[touch2 allObjects] objectAtIndex:0];
EDIT: to add information about touchesMoved
touchesBegan is called when one or more fingers is placed on the screen.
At this point you will need to determine which ball corresponds to each touch (by using the coordinates of each touch). You will need to store this mapping.
touchesMoved will be called continually as the fingers are moved across the screen. Using the mapping you calculated earlier, you can determine which ball corresponds to which UITouch and apply some movement to it as you see fit.
Perhaps you should read handling a complex multi-touch sequence in the apple docs.