I am currently using this code to get the locations of all the touches:
NSSet *allTouches = [event allTouches];
NSArray *allObjects=[allTouches allObjects];
for (int i=0;i<[allObjects count];i++)
{
UITouch *touch = [allObjects objectAtIndex:i];
CGPoint location = [touch locationInView: [touch view]];
//Add to array....
}
While testing it on the simulator (don't have an iPad now to test it), it works perfectly with single-touch. But when trying with multiple-touches, the first iteration is correct while the second iteration doesn't give the correct position.
i.e.
First touch: (536,163) correct
Second touch: (198,608) but should be somewhere around (148,345)
I have a feeling that I should change something with [touch locationInView: [touch view]]; to give the right location but I don't know what to change.
Any help is appreciated.
It's difficult to understand the issue from a set of coordinates without seeing your views, any subviews and where you're touching in that, but you should know that:
[touch locationInView:aView] gives the coordinates of the touch in the coordinate system of aView. That is, the coordinates you see are relative to the top left of aView which may not be what you're expecting. Try [touch locationInView:self], which is more common.
Have a look at the "Events and Touches" section of the Event Handling Guide for iOS. You generally don't need to iterate over that collection if you're trying to track multiple touches. iOS handles all that for you. You can use properties tapCount and phase to get information about whether touches have moved, how many fingers are down and so on.
Does any of that help?
Related
In my app, I allow the user to annotate a photo by adding arrows (custom ArrowView). There can be many arrows added, with various zoom & rotation.
I am trying implement selecting of arrow by touch. Currently, I am iterating & using
CGRectContainsPoint(arrowView.frame, touchPoint)
to decide which arrow to select based on a touch gesture.
But, this does not work well when some of the arrows are big & rotated to 45 degrees (since the frame becomes big).
Question:
I would like to use bounds of the arrow translated to parent co-ordinates instead of frame. How can I get this when scaling & rotation is applied?
Alternatively, is there a better method to solve this selection problem?
This code find the arrow under touchPoint:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
UIView *arrow = [self.view hitTest:touchPoint withEvent:event];
}
I have a UIImageView and I am trying to determine when a drag is performed, how far that drag is from the origin. I currently have this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:touch.view];
if(CGRectContainsPoint(myimage.frame, location) == 0){
}
else
{ //user didn't tap inside image}
The image itself does not move, but a person can take their finger, click on the image and then drag their finger. I am just trying to determine that drag distance.
If you want to calculate distance, you need to remember the point (store it somewhere) in touchesBegan if the user tapped on your image.
Then in touchesMoved or touchesEnd you will be able to get current point and calculate distance to your original point.
If you need to get distance from UIImageView origin, you can call [touch locationInView:myImage];
And I suggest you to use UIGestureRecognizer class instead of handling touches by yourself. They are simpler to implement.
in iPhone SDK there are touchesBegan, touchesEnded and touchesMoved functions that are called when a touch event appears. My problem is that when I put a finger on the screen and I'm not moving it there is no way to know if there is a finger on the screen or not. Is there a way to get current touch screen state?
In any of touchesBegan, touchesEnded and touchesMoved functions I can use fallowing code to know the state for every touch, but outside them I can't:|
NSSet *allTouches = [event allTouches];
for(GLuint index = 0; index < [allTouches count]; ++index)
{
UITouch *touch = [[allTouches allObjects] objectAtIndex:index];
if([touch phase] != UITouchPhaseCancelled)
{
CGPoint touchPoint = [touch locationInView:self];
//do something with touchPoint that has state [touch phase]
}
}
You should keep a list of all points where the touches currently are. Make sure you don't just retain the UIEvent or UITouch objects (they're not guaranteed to live long) - instead, create your own data data structure. Odds are all you need is to keep track of the points where touches are currently down.
If you don't want to fix your broken design, why doesn't keeping a running list of active touches solve your problem?
NSMutableSet *touches;
In touchesBegan you add them, in touchesEnded and touchesCancelled you remove them...
You might use a "global" object (i.e. singleton) to track those and synchronize data access. I cannot see how querying this set would be different than asking UIKit directly for this information.
If you need information on touches on standard UIKit objects (i.e. UIButton), you probably need to subclass those - and I am not sure if you can get the desired effect with all classes (as they - or their subviews - could handle touches in any way they want).
Hey guys, i ready many many questions about that point, but i really didn't get the right one yet.
So.. this is the problem..
This is my first project with cocos2d, so sorry for that.
I have one scene called Gameplay inside that i have one Layer with the name Grid and inside of this grid, have many many Block (Layer too).
I need check when you touch one Block, i do this before with Interface Builder, so when i call touchesBegin i have the exact touch in one view. But in cocos2D, i understand you have to check the position of the objects, and not hit test then right?!
So my touchesBegin is like this:
- (void)ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
//location = [[Director sharedDirector] convertCoordinate: location];
for(int i = 0; i < [arrAllBlocks count]; i++)
{
for (int j = 0; j < [[arrAllBlocks objectAtIndex:i] count]; j++)
{
Block *tempBlock = [[arrAllBlocks objectAtIndex:i] objectAtIndex:j];
CGRect mySurface = (CGRectMake(tempBlock.position.x, tempBlock.position.y, tempBlock.contentSize.width,tempBlock.contentSize.height));
if(CGRectContainsPoint(mySurface, location))
{
NSLog(#"Hit Positions %fl:%fl",location.x,location.y);
NSLog(#"Object Positions %fl:%fl",tempBlock.position.x,tempBlock.position.y);
NSLog(#"Object Color:%# hited", tempBlock.strName);
}
}
}
}
The first Problem is: This looks upsidedown! When i click in one of this blocks at the first line! I get the block at last line!! I Really dont get that! And the hit not seens perfect to me! And when i convertCoordinate this going even worst!
Someone can help me?! And sorry for bad english =/
There are two things to remember...
Cocos2D coordinate system's origin is bottom left corner.
By default, the anchor points of display elements are their centers.
So this is how I solved this problem:
Set the anchor points of the elements to be bottom left as well.
[block setAnchorPoint:ccp(0, 0)];
Use convertCoordinate in ccTouchesBegan.
-(BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint pt = [touch locationInView:[touch view]];
CGPoint ptConv = [[Director sharedDirector] convertCoordinate:pt];
}
Calculate the rectangle of the element and compare...
CGSize size = [block contentSize];
CGPoint point = [block position];
rect = CGRectMake(point.x, point.y, size.width, size.height);
if (CGRectContainsPoint(rect, ptConv))
{
// touched
}
It looks like the only step you are missing is to change the anchor point.
If you prefer not to change the anchor point, you need to change the way rectangle is calculated; adding and subtracting the half of width and height.
Hope it helps.
Remember that the coordinate system in Cocos2D is upside down from that of Cocoa. (Really, Cocoa is upside down to me, but it's just a convention).
I forget this all the time myself!
I have the following code to determine if a touch is within an image view in my table cell. However, it doesn't work. I compared the two with CGRectContainsPoint however, it doesn't work. Here is the code:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Declare the touch and get it's location
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self];
if (CGRectContainsPoint(myImageView.frame, touchLocation))
{
NSLog(#"Tapped image view");
}
}
Thanks for the help!
However, it doesn't work.
Please be more specific.
UITouch *touch = [touches anyObject];
Why not examine every touch, and not simply a random* pick of them?
*The documentation for anyObject says that you are not guaranteed which one it will give you. You are not even guaranteed that it will be random; it could be the same object every time. Murphy's Law says that, whether it is random or not, it will be the wrong one.
CGPoint touchLocation = [touch locationInView:self];
if (CGRectContainsPoint(myImageView.frame, touchLocation))
Your frame is in your superview's co-ordinate system; [touch locationInView:self] returns the touch point in your co-ordinate system. You want to test within bounds, which is in your co-ordinate system. The documentation explains the difference.
The problem is that you need to be calling [touch locationInView:myImageView] to get the point in the image views coordinate system. Then do your check to see if it's within the frame.
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self];
if ([touch view]==view) {
view.center=location;
}
write it in the touch moved event. thanx
Remember that when you're asking a touch for locationInView:, you're getting out a point relative to that view's frame. So, assuming the code snippet you gave was contained in a subclass of UIViewController you should be asking for
CGPoint touchLocation = [touch locationInView:self.view];
Which will give you a point relative to your view. The reason you want a point relative to your current view is because the frame of your image view is also relative to its parent view - the same view. So now it should work.
if (CGRectContainsPoint(myImageView.frame, touchLocation)) {
NSLog(#"Tapped image view");
}