UIPanGestureRecognizer get swipe distance in pixels - ios

I'm trying to track the horizontal distance that a user has swiped using a UIPanGestureRecognizer, but I'm having difficulty interpreting the results. Here is the code that I am using:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint startLocation;
if (recognizer.state == UIGestureRecognizerStateBegan) {
startLocation = [recognizer locationInView:self.view];
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint stopLocation = [recognizer locationInView:self.view];
CGFloat dx = stopLocation.x - startLocation.x;
NSLog(#"dx: %f", dx);
}
}
If I swipe left-to-right, I get output something like this:
dx: 50328911327402404790403072.000000
My screen is only 320 pixels wide, so my end result cannot be greater than 320. Is there a problem with my code or am I just interpreting this number incorrectly? How can I get this value stated in pixels? Thanks!

startLocation doesn't persist after handlePan: returns, so you're getting garbage.
Either declare startLocation as static or save it in an instance variable / property.

You can use UIPanGestureRecognizer as below:-
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
if ([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
firstX = [[sender view] center].x;
firstY = [[sender view] center].y;
}
translatedPoint = CGPointMake(firstX+translatedPoint.x, firstY);
[[sender view] setCenter:translatedPoint];
if ([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
CGFloat velocityX = (0.2*[(UIPanGestureRecognizer*)sender velocityInView:self.view].x);
CGFloat finalX = translatedPoint.x + velocityX;
CGFloat finalY = firstY;

Related

How can I control imageView's moving by PanGestureRecognizer?

I want to move imageView by PanGestureRecognizer like this
(imageView can be scaled)
If imageView's position is (0,0), it can't move.
If imageView's position x is over 60, it can't move more.
If imageView's position y is over 80, it can't move more.
When imageView's scale is restored(1.0), it's position is (0,0).
It is difficult to restrict imageView's moving and position.
What should I do?
Here is my code.
img = [UIImage imageNamed:[NSString stringWithFormat:#"a.jpg"]];
imgView = [[UIImageView alloc]initWithImage:img];
imgView.frame = CGRectMake(0,0, self.view.frame.size.width, 448);
imgView.userInteractionEnabled = YES;
[self.view imgView];
- (void)panAction : (UIPanGestureRecognizer *)sender {
CGPoint CGP = imgView.center;
if(newScale != 1.0 && CGP.x-160 != 0 && CGP.y-224 != 50){
CGPoint p = [sender translationInView:self.view];
CGPoint movedPoint = CGPointMake(imgView.center.x + p.x, imgView.center.y + p.y);
imgView.center = movedPoint;
[sender setTranslation:CGPointZero inView:self.view];
}
}
-(void)handlePinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer {
if([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
// Reset the last scale, necessary if there are multiple objects with different scales
lastScale = [gestureRecognizer scale];
}
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ||
[gestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGFloat currentScale = [[[gestureRecognizer view].layer valueForKeyPath:#"transform.scale"] floatValue];
// Constants to adjust the max/min values of zoom
const CGFloat kMaxScale = 2.0;
const CGFloat kMinScale = 1.0;
newScale = 1 - (lastScale - [gestureRecognizer scale]);
newScale = MIN(newScale, kMaxScale / currentScale);
newScale = MAX(newScale, kMinScale / currentScale);
CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], newScale, newScale);
[gestureRecognizer view].transform = transform;
lastScale = [gestureRecognizer scale]; // Store the previous scale factor for the next pinch gesture call
}
}
You must use the following condition check in your Pan Gesture action:
For you information, as you move the object, this panAction() method is called regularly at each pixel move.
- (void)panAction : (UIPanGestureRecognizer *)sender {
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan)
{
//Do something whatever you need to be done while the pan gesture starts
}
if ([(UIPanGestureRecognizer *)sender state] == UIGestureRecognizerStateChanged)
{
//Do something whatever you need to be done while the imageView object is in the moving state
}
if ([(UIPanGestureRecognizer *)sender state] == UIGestureRecognizerStateEnded){
//Do something you need to do as you end the pan gesture.
}
}

UIPanGestureRecognizer and UIPinchGestureRecogizer for zoom in AND move with bounce-pull back animation

I have UIImageView inside UIView.
please assume the user can only zoomin (not in this code).
if the uiimage is bigger the UIView, I need the animation that pull back the uiimage, like in the facebook app.
meaning , If user move the UIImageView up..when he lift the finger the UIImageView is pullback to cover the empty space on the bottom.
I tried to play with it, but..no luck.
thanks in advance
-(void)pinchGestureDetected:(UIPinchGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat scale = [recognizer scale];
[recognizer.view setTransform:CGAffineTransformScale(recognizer.view.transform, scale, scale)];
[recognizer setScale:1.0];
}
}
- (void)panGestureDetected:(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];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return ![gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]];
}
that one should work if your image is bigger than its container:
- (void)panGestureDetected:(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];
}
else if(state==UIGestureRecognizerStateEnded){
UIView *imageView = recognizer.view;
UIView *container = imageView.superview;
CGFloat targetX = CGRectGetMinX(imageView.frame);
CGFloat targetY = CGRectGetMinY(imageView.frame);
if(targetX>0){
targetX = 0;
}else if(CGRectGetMaxX(imageView.frame)<CGRectGetWidth(container.bounds)){
targetX = CGRectGetWidth(container.bounds)-CGRectGetWidth(imageView.frame);
}
if(targetY>0){
targetY = 0;
}else if(CGRectGetMaxY(imageView.frame)<CGRectGetHeight(container.bounds)){
targetY = CGRectGetHeight(container.bounds)-CGRectGetHeight(imageView.frame);
}
[UIView animateWithDuration:0.3 animations:^{
imageView.frame = CGRectMake(targetX, targetY, CGRectGetWidth(imageView.frame), CGRectGetHeight(imageView.frame));
}];
}
}

How to get the coordinate of a UIView

In my app, I use PanGesture.
Now, I have a UIImageView within my main view and I can drag my UIImageView within the main view.
To which axis in the main view I have to drag my UIImageView?
Try this to move your object
or link for best tutorials http://www.raywenderlich.com/6567/uigesturerecognizer-tutorial-in-ios-5-pinches-pans-and-more
- (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];
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint velocity = [recognizer velocityInView:self.view];
CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
CGFloat slideMult = magnitude / 200;
NSLog(#"magnitude: %f, slideMult: %f", magnitude, slideMult);
float slideFactor = 0.1 * slideMult; // Increase for more of a slide
CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor),
recognizer.view.center.y + (velocity.y * slideFactor));
finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width);
finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height);
[UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
recognizer.view.center = finalPoint;
} completion:nil];
}
}
you can use frame property of a UIView class.which gives you top,left,width and height of the view.
NSLog(#"view.frame.origin.x : %f",view.frame.origin.x);
NSLog(#"view.frame.origin.y : %f",view.frame.origin.y);
NSLog(#"view.frame.size.width : %f",view.frame.size.width);
NSLog(#"view.frame.size.height : %f",view.frame.size.height)
You can use below APIs to translate your points from one view to other and vice versa.
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;
- (IBAction)panGestureReceived:(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 ;)
} else if ([gesture state] == UIGestureRecognizerStateChanged) {
CGPoint myNewPositionAtTheEnd = [gesture locationInView:self.view];
// and now handle it ;)
}
}

UIView flipping by UIPanGestureRecognizer

I'm trying to use UIPanGestureRecognizer to flip an UIView. I'm using below code to handle flipping the view,
- (void)handlePan:(UIPanGestureRecognizer*)gesture{
CGPoint translation = [gesture translationInView:self.view];
NSLog(#"PAN X VALUE %f", translation.x );
double percentageOfWidth = translation.x / (gesture.view.frame.size.width / 2);
float angle = (percentageOfWidth * 100) * M_PI_2 / 180.0f;
CALayer *layer = testView.layer;
CATransform3D flipTransform = CATransform3DIdentity;
flipTransform.m34 = -0.002f;
flipTransform = CATransform3DRotate(flipTransform, angle, 0.0f, 1.0f, 0.0f);
layer.transform = flipTransform;
}
My problem is when i pan, sometimes there are some quick jumpings happen, I believe thats because translation.x(PAN X VALUE) value jumps from few points ahead, In my case i need it to be very smooth.
Any help greatly appreciated.
Thanks in advance.
You can use the gestureRecognizerShouldBegin method, which u can limit the UIPanGestureRecognizer sensitivity.
Example:
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer {
CGPoint translation = [panGestureRecognizer translationInView:self.view];
return fabs(translation.y) < fabs(translation.x);
}
Here's how I solved this for a cube rotation - just take the amount dragged and divide:
- (void)panHandle:(UIPanGestureRecognizer*)recognizer;
{
if ([recognizer state] == UIGestureRecognizerStateBegan)
{
CGPoint translation = [recognizer translationInView:[self superview]];
_startingX = translation.x;
}
else if ([recognizer state] == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:[self superview]];
CGFloat angle = -(_startingX - translation.x) / 4;
//Now do translation with angle
_transitionContainer.layer.sublayerTransform = [self->_currentMetrics asTransformWithAngle:angle];
}
else if ([recognizer state] == UIGestureRecognizerStateEnded)
{
[self transitionOrReturnToOrigin];
}
}

Does the bounds of a uiview change when a pinch gesture is used on it?

I am using the UIPinchGestureRecognizer to expand/reduce a uiview.
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scaleElement:)];
[pinchGesture setDelegate:self];
[element addGestureRecognizer:pinchGesture];
[pinchGesture release];
//Scale element method
- (void)scaleElement:(UIPinchGestureRecognizer *)gestureRecognizer {
UIView *element = [gestureRecognizer view];
[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan){
lastTouchPosition = [gestureRecognizer locationInView:element];
}
else if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged){
CGPoint currentTouchPosition = [gestureRecognizer locationInView:element];
CGPoint deltaMove = [self calculatePointDistancewithPoint1:currentTouchPosition andPoint2:lastTouchPosition];
float distance = sqrt(deltaMove.x*deltaMove.x + deltaMove.y*deltaMove.y);
float hScale = 1 - deltaMove.x/distance * (1-gestureRecognizer.scale);
float vScale = 1 - deltaMove.y/distance * (1-gestureRecognizer.scale);
if (distance == 0) {
hScale = 1;
vScale = 1;
}
element.transform = CGAffineTransformScale([element transform], hScale, vScale);
CGAffineTransform transform = CGAffineTransformMakeScale(hScale, vScale);
element.bounds = CGRectApplyAffineTransform(element.bounds, transform);
[gestureRecognizer setScale:1];
lastTouchPosition = currentTouchPosition;
}
if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) {
NSLog(#"scaling over");
NSLog(#"bounds = %#",NSStringFromCGRect(element.bounds));
NSLog(#"frame = %#", NSStringFromCGRect(element.frame));
}
NSLog(#"scalePiece exit");
}
//adjustAnchorPointForGestureRecognizer method
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
UIView *elementToAdjust = gestureRecognizer.view;
[self.view bringSubviewToFront:gestureRecognizer.view];
CGPoint locationInView = [gestureRecognizer locationInView:elementToAdjust];
CGPoint locationInSuperview = [gestureRecognizer locationInView:elementToAdjust.superview];
elementToAdjust.layer.anchorPoint = CGPointMake(locationInView.x / elementToAdjust.bounds.size.width, locationInView.y / elementToAdjust.bounds.size.height);
elementToAdjust.center = locationInSuperview;
}
}
Console print:
bounds = {{0, 0}, {178.405, 179.018}}
frame = {{300.642, 566.184}, {192.899, 194.227}}
Why isn't the bounds adjusting when the frame is changing ?
Does it have anything to do with auto resizing masks as I have subviews to this view ?
This has nothing to do with UIPinchGestureRecognizer. This has everything to do with your setting the transform to perform scaling. Changing the transform does not change bounds. It just changes how this view's coordinate space (bounds) maps to the superview's coordinate space (frame). If you need bounds to match frame, you have to change one of them directly, not use transform. That said, you should generally use transform because it's much faster.
EDIT
If you don't mean to scale, but rather mean to resize the view, call setBounds:. You can find the new bounds by applying the transform to the bounds rather than the element.
CGPoint currentTouchPosition = [gestureRecognizer locationInView:element];
CGPoint deltaMove = [self calculatePointDistancewithPoint1:currentTouchPosition andPoint2:lastTouchPosition];
...
CGAffineTransform transform = CGAffineTransformMakeScale(hScale, vScale);
self.bounds = CGRectApplyAffineTransform(self.bounds, transform);

Resources