-(void)move:(UIPanGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:recognizer.view];
[recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
}
There are several methods you can use;
Firstly, you can add a transparent subview in your main view and assign the pan gesture to that subview. Hence, only the pan gesture on subview will be recognized, and you can translate your main view directly.
Like this:
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:self.panView];
[self.mainView setTransform:CGAffineTransformTranslate(self.mainView.transform, translation.x, translation.y)];
[recognizer setTranslation:CGPointZero inView:self.panView];
}
(I didn't make panView completely transparent for show purposes, you should use clearColor instead of setting alpha to 0.)
(And obviously, panView is a subview of mainView, hence when the mainView is translated, panView also is translated.)
Secondly, you can customize your UIPanGestureRecognizer to implement touchesBegan: and raise a flag (like shouldRecognizeNow and check in move:method) if you don't want the touch to be recognized when started in particular place. (You may want to check CGRectContainsPoint: method.)
I'm not going into details of that, here's a link for starting:
https://stackoverflow.com/a/19145354/3227743
Related
I have a scrollView with some UIViews as subviews that I drag around. The problem is that the subviews is rather small, and when dragging them, you can't see them because the finger is in the way.
How do I offset the view a little bit upwards while dragging?
Thanks
if (recognizer.state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:self];
draggingView.center = CGPointMake(draggingView.center.x + translation.x,
draggingView.center.y + translation.y);
[recognizer setTranslation:CGPointZero inView:self];
}
Try following code
CGPoint touchPoint = [recognizer locationInView:self];
try changing touchPoint
I am using the locationInView to set the position of my bouton when the user release it. After release, I give the location stored before but in fact, my button is not going back to the correct position.
This my code:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer{
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
static CGPoint startLocation;
if (recognizer.state == UIGestureRecognizerStateBegan) {
startLocation = [recognizer locationInView:self.view];
NSLog(#"Began: %d" #"-" #"%d", (int)startLocation.x , (int)startLocation.y);
}
if (recognizer.state == UIGestureRecognizerStateEnded)
{
NSLog(#"Ended Bef: %d" #"-" #"%d", (int)startLocation.x, (int)startLocation.y);
recognizer.view.center = CGPointMake(startLocation.x, startLocation.y);
startLocation = [recognizer locationInView:self.view];
NSLog(#"Ended Aft: %d" #"-" #"%d", (int)startLocation.x, (int)startLocation.y);
}
}
In fact, the instruction:
recognizer.view.center = CGPointMake(startLocation.x, startLocation.y);
give a wrong effect. Someone know why?
A couple of thoughts:
I'd suggest making sure you capture startLocation before you do any changing of the center.
You're using the location of the user's touch for startLocation. You really should initialize this with the center of the recognizer.view. It's exceedingly unlikely that the user started their gesture precisely in the center of the button. And as a result, you're unlikely to return back at the original location.
Somewhat unrelated, but:
You don't need to use CGMakePoint when resetting the center of recognizer.view in the UIGestureRecognizerStateEnded clause. You can use CGPointMake if you really want, but it's unnecessary. You can just use startLocation, if you want.
You might want to animate the returning of the view back to that startLocation. It's jarring to have it immediately go there.
As an aside, if you've saved startLocation, you don't need to continually reset the translation. Just use startLocation plus translation. Seems more clear to me, but clearly that's subjective.
I personally think NSStringFromCGPoint is very useful when logging CGPoint structures.
So, I'd suggest:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer
{
static CGPoint startLocation;
if (recognizer.state == UIGestureRecognizerStateBegan)
{
startLocation = recognizer.view.center;
NSLog(#"Began: %#", NSStringFromCGPoint(startLocation));
}
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(startLocation.x + translation.x,
startLocation.y + translation.y);
if (recognizer.state == UIGestureRecognizerStateEnded)
{
NSLog(#"Ended Bef: %#", NSStringFromCGPoint(startLocation));
[UIView animateWithDuration:0.25
animations:^{
recognizer.view.center = startLocation;
}];
CGPoint finalLocation = [recognizer locationInView:self.view];
NSLog(#"Ended Aft: %#", NSStringFromCGPoint(finalLocation));
}
}
I am new to iOS, I am using UIPanGestureRecognizer in my project. In which I have a requirement to get current touch point and previous touch point when I am dragging the view. I am struggling to get these two points.
If I use touchesBegan method Instead of using UIPanGestureRecognizer, I could get these two points by the following code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint touchPoint = [[touches anyObject] locationInView:self];
CGPoint previous=[[touches anyObject]previousLocationInView:self];
}
I need to get these two points in UIPanGestureRecognizer event fire method. How can I achieve this? please guide me.
You can use this:
CGPoint currentlocation = [recognizer locationInView:self.view];
Store previous location by setting current location if not found and adding current location everytime.
previousLocation = [recognizer locationInView:self.view];
When you link an UIPanGestureRecognizer to an IBAction, the action will get called on every change. The gesture recognizer also provides a property called state which indicates if it's the first UIGestureRecognizerStateBegan, the last UIGestureRecognizerStateEnded or just an event between UIGestureRecognizerStateChanged.
To solve your problem, try it like the following:
- (IBAction)panGestureMoveAround:(UIPanGestureRecognizer *)gesture {
if ([gesture state] == UIGestureRecognizerStateBegan) {
myVarToStoreTheBeganPosition = [gesture locationInView:self.view];
} else if ([gesture state] == UIGestureRecognizerStateEnded) {
CGPoint myNewPositionAtTheEnd = [gesture locationInView:self.view];
// and now handle it ;)
}
}
You may also have a look at the method called translationInView:.
If you don't want to store anything you can also do this :
let location = panRecognizer.location(in: self)
let translation = panRecognizer.translation(in: self)
let previousLocation = CGPoint(x: location.x - translation.x, y: location.y - translation.y)
There is a function in UITouch to get the previous touch in the view
(CGPoint)locationInView:(UIView *)view;
(CGPoint)previousLocationInView:(UIView *)view;
You should instantiate your pan gesture recognizer as follows:
UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
Then you should add panRecognizer to your view:
[aView addGestureRecognizer:panRecognizer];
The - (void)handlePan:(UIPanGestureRecognizer *)recognizer method will be called while the user interacts with the view. In handlePan: you can get the point touched like this:
CGPoint point = [recognizer locationInView:aView];
You can also get the state of the panRecognizer:
if (recognizer.state == UIGestureRecognizerStateBegan) {
//do something
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
//do something else
}
I have a UIView object that can be dragged around using UIPanGestureRecognizer, but I only want it to be able to move up 3/4 of the screen. I don't want to it be clipped, but to get to a certain point and not be able to be dragged any further. What I have so far allows it to only move on the Y axis (which is desired).
- (IBAction)panGesture:(UIPanGestureRecognizer *)recognizer
{
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
Thanks for any help.
So just check whether the new Y coordinate would be too small. Don't change the view if it would be too small:
- (IBAction)panGesture:(UIPanGestureRecognizer *)recognizer
{
CGPoint translation = [recognizer translationInView:self.view];
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
CGPoint center = recognizer.view.center;
center.y += translation.y;
if (center.y < self.yMin)
return;
recognizer.view.center = center;
}
Its work fine for me.
CGPoint currentTouchPoint = [gesture translationInView:self.bottomView];
if (fabsf(currentTouchPoint.x) > fabsf(currentTouchPoint.y)) {
// avoid horizontal movement of pan geuture.
return;
}
thanks,
Naveen Shan
Implement the following gesture delegate and check your condition inside it. Returning YES or NO from this delegate will make the gesture active and inactive.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
I'm using UIPinchGestureRecognizer to detect pinch gestures, something like:
- (void) initPinchRecon {
UIPinchGestureRecognizer *pinchRecognizer = [[[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:#selector(Perform_Pinch:)] autorelease];
[self addGestureRecognizer:pinchRecognizer];
[pinchRecognizer setScale:20.0f];
}
- (void) Perform_Pinch:(UIPinchGestureRecognizer*)sender{
NSLog(#"PINCH");
}
And it works well to detect a simple pinch gesture: It's possible to determine (or define myself) the angle or orientation of the pinch gesture ?, for example, to differentiate between an horizontal and an vertical pinch gesture ?
A very simple solution is to implement the gesture handler like this:
-(void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer {
if (recognizer.state != UIGestureRecognizerStateCancelled) {
if (recognizer.numberOfTouches == 2) {
CGPoint firstPoint = [recognizer locationOfTouch:0 inView:recognizer.view];
CGPoint secondPoint = [recognizer locationOfTouch:1 inView:recognizer.view];
CGFloat angle = atan2(secondPoint.y - firstPoint.y, secondPoint.x - firstPoint.x);
// handle the gesture based on the angle (in radians)
}
}