UIView flipping by UIPanGestureRecognizer - ios

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

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 to implement scale and rotate an UIView

There is a UIView A. I put a icon on view A and try to use pan gesture to scale and rotate this view A. The scale function works fine but I can't make rotation work. The code is as following. Any help will be appreciated. thanks
- (void)scaleAndRotateWatermark:(UIPanGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateChanged
|| gesture.state == UIGestureRecognizerStateEnded)
{
UIView *child = gesture.view;
UIView *view = child.superview;
CGPoint translatedPoint = [gesture translationInView:view];
CGPoint originCenter = child.center;
CGPoint newCenter = CGPointMake(child.centerX+translatedPoint.x, child.centerY+translatedPoint.y);
float origX = originCenter.x;
float origY = originCenter.y;
float newX = newCenter.x;
float newY = newCenter.y;
float originDis = (origX*origX) + (origY*origY);
float newDis = (newX*newX) + (newY*newY);
float scale = newDis/originDis;
view.transform = CGAffineTransformScale(view.transform, scale, scale);
// rotation calulate here
// need your help
// end of rotation
[guesture setTranslation:CGPointZero inView:_videoPreviewLayer];
}
}

UIPanGestureRecognizer get swipe distance in pixels

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;

UIPanGestureRecognizer - translationInView with CATransform3D

I'm trying to implement a page flipping animation using a UIPanGestureRecognizer. Here's the code:
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:self.view];
CGPoint translation = [recognizer translationInView:self.view];
CGPoint velocity = [recognizer velocityInView:self.view];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
switch (recognizer.state) {
case UIGestureRecognizerStateChanged:
{
self.currentTranslation = self.currentTranslation + translation.x;
//only pan left
if (self.currentTranslation > 0.0) {
self.currentTranslation = 0.0;
}
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / -2000;
self.currentRotation = self.currentTranslation/2 * M_PI / 180.0f;
//dont rotate past -90 degrees
if (self.currentRotation <= -M_PI/2) {
self.currentRotation = -M_PI/2+0.0001;
}
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, self.currentRotation, 0.0f, 1.0f, 0.0f);
float ypos = self.view.layer.position.y;
self.view.layer.anchorPoint = CGPointMake(0, 0.5);
self.view.layer.position = CGPointMake(0, ypos);
self.view.layer.transform = rotationAndPerspectiveTransform;
break;
}
default:
break;
}
}
The animation works, and the page turns as I drag to the left. However, even when I move at a steady, slow pace with the gesture, the page starts to turn more rapidly. I want the page to turn "linearly" as the touch moves, like the Flipboard app. How can I control the translation to that it doesn't get accelerated?
The translation is accumulated. Add this to your code after the case UIGestureRecognizerStateChanged.
[recognizer setTranslation:CGPointZero inView:self.view];

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

Resources