iPhone SDK - Where did I finish touching the screen? - iphone

Is there any way for the touchesEnded method to tell me the position of where I lifted my finger?
Also, can it tell me which finger was lifted if I had 2 (or more) on the device? (e.g. if I put finger 1 down, then finger 2 down, then lifted finger 2 but held down finger 1, could it tell me that I have ended finger 2?)
Thanks
Jon

Look at the touch methods that are inherited by UIViews, specifically touchesEnded:withEvent: will tell you when / where the touches ended (i.e. where you lifted your finger).
Just override these methods in your view controller like this and you can find out where the touch refers to :
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Get a touch
UITouch *touch = [touches anyObject];
// Where did it end?
CGPoint endedAt = [touch locationInView:[self view]];
...
The touch object will be the same (isEqual:) to the touch that was sent in the touchesBegan:withEvent: method. This should let you track multiple touches if you store the touches that you are interested in in your touchesBegan and compare them in your touchesEnded

Related

iOS - How to drag element during animation

i need to drag an element during an animation. The element fall from the top of the screen and i need the user can drag it wherever he want, even during animation
Thanks
You can use the touchesBegan method to detect when the user touches the element.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (touch != nil && (touch.view == elementView))
//do your stuff
}
Then set the element's position to the touch location, and remove the animation.
elementView.center = [touch locationInView:self.view];
[elementView.layer removeAllAnimations];
This should work. Then you can use the similar touchesMoved method to update the position during the drag.
Since you're using the UIView block based animations, try using:
animateWithDuration:delay:options:animations:completion:
with the UIViewAnimationOptionAllowUserInteraction option.

How to get effective Bounds of a subview in its parent view's co-ordinate system

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];
}

TouchesMoved With 2 Fingers

I am trying to make a simple landscape "split screen" app where two players can play at once (each player gets one half of the screen), but I am having trouble tracking both touches at the same time. This is the code I am trying to use:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint point = [touch locationInView:self.view];
if (point.x < 240) {
[player1 updatePoint:point];
} else {
[player2 updatePoint:point];
}
}
}
But I am obviously doing something wrong. Although this code works fine, it will only track one finger and move the player on the side of the screen the finger is on. What is my code lacking? Is this task more difficult to pull off then I think it is?
Did you set UIView's multipleTouchEnabled to YES?
multipleTouchEnabled should be set to YES for the UIView.

Determine How far drag point is

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.

When the user has two fingers on the screen and lifts one I want nothing to happen

enough is enough.
like the title says, I'm in a bit of a pickle.
so here's the outline of my problem. I have this ship right. It rests in the center bottom of the screen (240,0). When the user touches to the right at a point greater than 240 the ship moves right. And left if the user touches at a point less than 240. HOWEVER this is great when there's only one finger on the screen at a time. I need it to where if the user touches right, doesn't lift their finger, then touches left (OH CRAP THERE'S TWO FINGERS ON THE SCREEN) the ship keeps moving right until they lift their right finger, then suddenly the ship moves left towards the second touch.
I'm using timers to add/subtract a number from the current x coordinate to get it to move.
This is what I have in a nutshell: (Don't laugh or hate I'm a noob)
-(void)moveShipLeft:(id)sender {
shipView.center = CGPointMake(shipView.center.x - 2, 320 - (shipView.image.size.height / 2));
}
-(void)moveShipRight:(id)sender {
shipView.center = CGPointMake(shipView.center.x + 2, 320 - (shipView.image.size.height / 2));
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if (240 < location.x){rightTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(moveShipRight:) userInfo:nil repeats:YES];}
if (240 > location.x){leftTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(moveShipLeft:) userInfo:nil repeats:YES];}
[shipView setCenter:shipView.center];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (rightTimer != nil) //Kill the timer that goes right upon touch removal
[rightTimer invalidate];
rightTimer = nil;
if (leftTimer != nil) //Kill the timer that goes left on touch removal
[leftTimer invalidate];
leftTimer = nil;
}
I'm trying to fully replicate the controls for the game "Radiant" if its any help.
I will seriously love you forever if you help.
Just to clarify, I want this to happen:
user touches the right side of screen
ship moves right
user touches left side of screen with second finger
while the ship is still moving right because the user hasn't lifted their first touch, the user then lifts the first touch
THEN the ship instantly changes course to move left towards the second touch
right now I have multi touch enabled, so now it works like this:
user touches the right side of screen
ship moves right
user touches left side of screen with second finger
ship moves left then user lift first touch
ship is stopped in its tracks even though the user hasn't lifted the second touch
First off, about not activating the leftTimer if the rightTouch is not released.
You could set up two Global Touches. So, if [touch locationInView:self.view] position blah is > 250 globalRightTouch = touch. Same for left.
THen when you hit the right side - you assign the touch to the global Right, and the ship starts to move right -- then you touch the left side simultaneously -- so another touches began thing starts - so you assign it to the globalLeftTouch. Then you can go something like: if(!globalRightTouch){start leftTimer) and vise versa.
In your touhcesEnded function - you are telling the leftTimer to kill if it is not null on touches end - so even if you have your left touch down still -- you are telling both timers to kill on any touch release. You just need to be a little more specific with your touches ended.
Then in your touches ended code you need to go something along the following:
UITouch *touch = [[event allTouches] anyObject];
if (rightTimer != nil && touch == globalRightTouch){ //Kill the timer that goes right upon touch removal
[rightTimer invalidate];
rightTimer = nil;
if(globalLeftTouch)
leftTimerStartFunction //I dont know what your variables are sorry
}
if (leftTimer != nil && touch == globalLeftTouch){ //Kill the timer that goes left on touch removal
[leftTimer invalidate];
leftTimer = nil;
if(globalRightTouch){
rightTimerStartFunction //I dont know what you variables are sorry
}
}
}
so essentially you want to say - If I let go of a touch - check which one it is and kill the timer for that touch if it is not null and if there is another touch currently on the screen - start the timer for that side.
Hope this helps,
Cheers,
Michael
Each UITouch is unique from the time the user starts touching until they stop. So your problem is really this line:
UITouch *touch = [[event allTouches] anyObject];
You don't want just any touch. You want a touch that is the same touch you've been moving toward, if it exists. Look for that touch in the set, and if it's not there start moving towards another touch.
Here is a real/pseudo code version - hope it helps...
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)even{
UITouch *touch = [touches anyObject];
if(touch.x < 240){
globalTouchLeft = touch;
if(!globalTouchRight){
startLeftTimer; //again I don't know what your timere/variable is
}
}else if(touch.x >= 240){
globalTouchRight = touch;
if(!globalTouchLeft){
startRightTimer; //again I don't know what your timere/variable is
}
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if(touch == globalLeftTouch){
stopLeftTimer
globalLeftTouch = nil;
if(globalRightTouch){
startRightTimer;
}
}
if(touch == globalTouchRight){
stopRightTimer
globalRightTouch = nil;
if(globalLeftTouch){
startLeftTimer;
}
}
}
cheers,
Michael O'Brien