Touch locations UIPinchGestureRecognizer - ios

I'm trying to resize an image using the UIPinchGesture recognizer and in order to carry that out I need to find the location of the center point upon which the pinching is focused on.
Originally I thought about creating a midpoint calculation for the center point based on the two touched points. The problem is that for some reason the returned points using the touch indexes are not the touch locations that are applied on screen.
For example, when I tried zooming using a touch that was approximately at (333, 187) and another at (1000, 563) the returned locations of the touches were (496, 279) and (170, 95).
What exactly are UITouch 1 and UITouch 2 the indexes of? How can I find the center-point value?
func handlePinchGesture(gesture: UIPinchGestureRecognizer){
// Finds the midpoint location of the pinch gesture
var touch1 = gesture.locationOfTouch(0, inView: self.view)
var touch2 = gesture.locationOfTouch(1, inView: self.view)
var midPointX = (touch1.x + touch2.x)/2
var midPointY = (touch1.y + touch2.y)/2
var touchedPoint = CGPointMake(midPointX, midPointY)
}

How can I find the center-point value
You don't have to find it. The gesture recognizer gives it to you. It is the gesture recognizer's locationInView:.

You can use the following code to get the touch location:
#objc func onGesture(gesture: UIPinchGestureRecognizer) {
print("Location", gesture.location(ofTouch: 0, in: nil))
}

CGPoint centerPoint = [recognizer locationInView: self.view];
Apple says:
The returned value is a generic single-point location for the gesture computed by the UIKit framework. It is usually the centroid of the touches involved in the gesture.
This will give you the center. Hope this helps.. :)

Related

How to disable second touch in an SpriteKit game?

The player drags a sprite in my game but when accidentally touch the screen with a second finger it screws the movement obviously.
I used the following solutions for disable the second touch, but unfortunately it doesn't work:
//--------------
-(void)touchesBegan:(NSSet*) touches withEvent:(UIEvent*) event {
if (touches.count == 1 && draggedNode == nil) {
CGPoint pos = [[touches anyObject] locationInNode:self];
SKNode * touchedNode = [self nodeAtPoint:pos];
if([touchedNode.name isEqual: #"shooterBall"]){
draggedNode = touchedNode;
}
draggedNodeOffset = CGPointMake(draggedNode.position.x - pos.x, draggedNode.position.y - pos.y);
}
}
//--------------
-(void)touchesMoved:(NSSet*) touches withEvent:(UIEvent*) event {
if (touches.count <= 1) {
CGPoint pos = [[touches anyObject] locationInNode:self];
draggedNode.position = CGPointMake(pos.x + draggedNodeOffset.x, pos.y+draggedNodeOffset.y);
}
}
//--------------
-(void)touchesEnded:(NSSet*) touches withEvent:(UIEvent*) event {
draggedNode = nil;
}
//--------------
Do you have any solution for this?
Thanks your help in advance!
You want to implement UIPanGestureRecognizer in your scene. It will allow you to track the location of the user's touch and at the same time control other "stray" touches: UIPanGestureRecognizer Documentation
After you initialize it, you need to implement a method to handle the user's pans. You will have to set flags inside of this method to control when the swipe started/ended. I think this answer on StackOverflow gave a really good explanation of using it (with Swift). BTW, when you initialize it, you should set the gesture recognizer's property maximumNumberOfTouches to 1 (that will cause it to ignore other touches while the user is panning).
The trickier part will be to translate the same code you wrote before to gesture recognizer. The difference is that your handler will be called only once for each "swipe" or "pan", while the touches method you are using now is called each time there is a "touch". There are a few ways to proceed at this point, and you could try whatever you like, but I think that this would be the easiest way to go once you have your gesture recognizer set up (spoiler):
make sure the gesture recognizer is an instance variable so you can access it from all methods.
go to the update: method and make an if statement that checks if gesture.state == UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged
use the same algorithm that you had before in this if statement. To check the location that the touch is at use the method: locationInView:. Use self.view as the parameter.
Hope this helped! good luck.

Please help me get a grip on UIGestureRecognizers in swift

I am having the hardest time figuring out gesture recognizers and such on iOS. Unfortunately a lot of the documentation by apple appears to be in Objective-C and/or it doesn't give you examples that show what values can go in. Could you show me some examples of how to the the following things.
Get the current position of each touch event on the screen. If the finger isn't down then return false.
Make a direction recognizer other then the 4 main directions. Currently my code looks like this
var leftSwipe = UISwipeGestureRecognizer(target: self, action: Selector("HandleSwipes:"))
leftSwipe.direction = .Left
view.addGestureRecognizer(leftSwipe)
However what if I wanted to detect diagonal movement? Their isn't a .Diagonal. So the detection of a gesture works in the direction (0.5, 0.5).
Going back to the code I put before I have a function that I check the direction in
func HandleSwipes(sender: UISwipeGestureRecognizer) {
if (sender.direction == .Left) {
Label.text = "Left"
}
}
What if I want this swipe to only work for the 2nd finger down? Also how would I get the ending, and starting position of that gesture? (preferably inside of that function)
How can I find out how long it has taken the finger to do the gesture (getting from point A to point B).
I am not that familiar with swift, but in objective-c, this is how you will obtain the current position of a touch event.
CGPoint _originalCenter;
-(void)handlePan:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
// if the gesture has just started, record the current centre location
_originalCenter = self.center;
}
Hope this helps answer the first part of your question.

Trying to understand TranslationInView

In my UITableViewCell subclass I add a pan gesture and in gestureRecognizerShouldBegin method I checked self.frame.origin.x and self.frame.origin.y both are 0.000000 and 0.000000and after applying TranslationInView CGPoint translation = [gestureRecognizer translationInView:[self superview]]; I am getting x=-4.000000 and y=0.000000
How TranslationInView work, I am trying to wrap my head around it, when I am getting the correct location of cell 0.0 and 0.0 because the first cell will have 0.0 and 0.0, why I need TranslationInView.
TranslationInView is a method of UIPanGestureRecognizer and it tells you how far the touch moved since it was last reset. It resets when the touch goes down or if you reset it yourself.
For example
- (void) pan: (UIPanGestureRecognizer *) recognizer
{
if ((recognizer.state == UIGestureRecognizerStateChanged)||(recognizer.state == UIGestureRecognizerStateEnded)) {
CGPoint translation = [recognizer translationInView:self];
}
}
The CGPoint traslation gets increased/decreased the distance that the gesture has moved.

UIPanGestureRecognizer not working as expected with multiple pans

Essentially, what I want to do is to move a view around to follow the user's pan. This works fine as long as the same pan object is being used. The problem comes when the user releases and than starts another pan.
According to the documentation, the value in translationInView is relative to the position at the start of the pan.
So my strategy for handling this was to add two properties to my view so I can tell whether the same pan object is being used and what the reference location is. The self object is the object being moved. It is a UIView subclass.
CGPoint originalPoint;
if (pan == self.panObject) {
//If the pan object is the same as the one in the property, use the saved value as the reference point.
originalPoint = CGPointMake(self.panStartLocation.x, self.panStartLocation.y);
} else {
//If the pan object is DIFFERENT, set the originalPoint from the existing center.
//self.center is in self.superview's coordinate system.
originalPoint = CGPointMake(self.center.x, self.center.y);
self.panStartLocation = CGPointMake(originalPoint.x, originalPoint.y);
self.panObject = pan;
}
CGPoint translation = [pan translationInView:self.superview];
self.center = CGPointMake(originalPoint.x+translation.x, originalPoint.y+translation.y);
This scheme doesn't work because each pan object apparently is the same object. I've spent a bit of time in the debugger verifying this, and that seems to be true. I thought the pan object would be different for each touch. So since this doesn't work, what is the alternative?
I solved it. Here is the corrected code:
CGPoint originalPoint;
if (pan.state == UIGestureRecognizerStateBegan) {
originalPoint = CGPointMake(self.center.x, self.center.y);
self.panStartLocation = CGPointMake(originalPoint.x, originalPoint.y);
} else {
originalPoint = CGPointMake(self.panStartLocation.x, self.panStartLocation.y);
}
CGPoint translation = [pan translationInView:self.superview];
self.center = CGPointMake(originalPoint.x+translation.x, originalPoint.y+translation.y);
EDIT: A better approach is to take advantage of the fact that the gesture recognizer allows you to set the translation:
[sender setTranslation:CGPointMake(0.0, 0.0) inView:self.pieceBeingMoved];
Do this when you move your item, and then the new translation next time will be relative to the position you just moved to.

How do I get the tap coordinates on a custom UIButton?

I'm using XCode 4.4 developing for iOS 5 on an iPad and am using the Storyboard layout when creating my custom button.
I have the touch event correctly working and logging but now I want to get the x/y coordinates of the tap on my custom button.
If possible, I'd like the coordinates to be relative to the custom button instead of relative to the entire iPad screen.
Here's my code in the .h file:
- (IBAction)getButtonClick:(id)sender;
and my code in the .m file:
- (IBAction)getButtonClick:(id)sender {
NSLog(#"Image Clicked.");
}
Like I said, that correctly logs when I tap the image.
How can I get the coordinates of the tap?
I've tried a few different examples from the internet but they always freeze when it displays a bunch of numbers (maybe the coordinates) in the log box. I'm VERY new to iOS developing so please make it as simple as possible. Thanks!
To get touch location you can use another variant of button action method: myAction:forEvent: (if you create it from IB interface note "sender and event" option in arguments field: )
Then in your action handler you can get touch location from event parameter, for example:
- (IBAction)myAction:(UIButton *)sender forEvent:(UIEvent *)event {
NSSet *touches = [event touchesForView:sender];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:sender];
NSLog(#"%#", NSStringFromCGPoint(touchPoint));
}
Incase of Swift 3.0 the accepted answer works same except syntax will be changed as follows:
Swift 3.0:
#IBAction func buyTap(_ sender: Any, forEvent event: UIEvent) {
let myButton = sender as! UIButton
let touches = event.touches(for: myButton)
let touch = touches?.first
let touchPoint = touch?.location(in: myButton)
print("touchPoint\(touchPoint)")
}
For your overall coordinates (with reference to the screen), you need to create a CGPoint that contains the coordinates of your touch. But to do that, you need to get that touch first. So start by getting the touch event, then by making that point using the locationInViewmethod. Now, depending on when you want to log the touch - when the user touches down, or when they lift their finger -, you have to implement this code in the touchesBegan or touchesEnded method. Let's say you do touchesEnded, which passes an NSSet cales "touches" containing all the touch events.
UITouch *tap = [touches anyObject];
CGPoint touchPoint = [tap locationInView:self.view];
"touchPoint" will now contain the point at which the user lifts their finger. To print out the coordinates, you just access the x and y properties of that point:
CGFloat pointX = touchPoint.x;
CGFloat pointY = touchPoint.y;
NSLog(#" Coordinates are: %f, %f ", pointX, pointY);
That should output the coordinates of the touch. Now to have it be referenced to whatever button you're using, I would suggest you just manually subtract the values for the button's coordinates from the point. It seems like a simple solution, and honestly I don't know a way of getting coordinates with reference to another object, unless you make a view based on that object, and pass it to locationInView instead of self.view.
For more info on touches, there's a great set of tutorials here.

Resources