UIPanGestureRecognizer not working on iPad? - ipad

I have a UIPanGestureRecognizer code below:
self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panThis:)];
self.panRecognizer.delegate = self;
[self.view addGestureRecognizer:self.panRecognizer];
- (void)panThis:(UIPanGestureRecognizer *)recognizer
{
switch (recognizer.state)
{
case UIGestureRecognizerStateBegan:
{
CGPoint panStartPoint = [recognizer translationInView:self.view];
NSLog(#"Pan Began at %#", NSStringFromCGPoint(panStartPoint));
break;
}
default:
break;
}
}
It works find on iPhone, but on iPad, it can't recognize the pan gesture and keep logging
Pan Began at {0, 0}
Pan Began at {0, 0}
Pan Began at {0, 0}
Does anything wrong with my code? Thanks a lot

this is my code.. it works. give a try.
- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
NSLog(#"handlePan");
//CGPoint p;
switch (recognizer.state) {
case UIGestureRecognizerStateBegan:
NSLog(#"UIGestureRecognizerStateBegan");
break;
case UIGestureRecognizerStateEnded:
// All fingers are lifted.
break;
default:
break;
}
UIView * inView = recognizer.view;
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];
///relative to view.
CGPoint center = inView.center;
NSLog(#"handlePan %f %f", center.x, center.y);
}

Related

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

Pan Gesture Recognizer reset

I've added a pan gesture to my button, when i move it without any additional code, everything is well, but when i add some piece of code, which is commented in the example below, button starts reseting to its origin position.
Why is this happening? What's the reason for this?
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
switch([recognizer state]){
case UIGestureRecognizerStateBegan: {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setFrame:recognizer.view.frame];
[button setBackgroundColor: [UIColor redColor]];
// [self.view insertSubview:button belowSubview:recognizer.view];
_tempButton = button;
}break;
case UIGestureRecognizerStateChanged: {
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];
}break;
}
}
The code that you have added at the UIGestureRecognizerStateChanged case, move it in the header of your Action Method:
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];
After that another thing for you to do is to make another Case in your Switch Method:
//This checks if you ended the pan gesture (removed finger from object)
case 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];
}
So what I did above in the UIGestureRecognizerStateEnded state is that, i took the final point where the user sent the image. After that, i set the center of the image equal to the point that the image was the last moment. So now the image wont return to the previous point but it will remain where the user will take it.

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

Rotation of view while dragging

I want to slightly rotate a UIView when it's being dragged. I managed to do the dragging using a UIPanGestureRecognizer. I also tried to Rotate using CGAffineTransformRotate and it worked. However, when i apply both dragging and rotation, the UIView rotates only and it doesn't get dragged around the super view. Here is what i'm doing in the gesture handler:
CGPoint translation = [gesture translationInView:self.view];
// to drag
gesture.view.center = CGPointMake(gesture.view.center.x + translation.x, gesture.view.center.y + translation.y);
// to rotate
gesture.view.transform = CGAffineTransformRotate(gesture.view.transform, degreesToRadians(translation.x)/4);
// return to default so that it doesn't accumulate
[gesture setTranslation:CGPointMake(0, 0) inView:self.view];
How can i fix this ?
EDIT:
here is the entire code:
- (void)handlePan:(UIPanGestureRecognizer*)gesture{
if (gesture.state == UIGestureRecognizerStateBegan) {
// Save initial post center for snapping
point = CGPointMake(gesture.view.center.x, gesture.view.center.y);
} else if (gesture.state == UIGestureRecognizerStateChanged){
// Translate user movement across the screen to dragging coordinates
CGPoint translation = [gesture translationInView:self.view];
gesture.view.center = CGPointMake(gesture.view.center.x + translation.x, gesture.view.center.y + translation.y);
CGAffineTransform rotate = CGAffineTransformRotate(gesture.view.transform, degreesToRadians(translation.x)/4);
gesture.view.transform = rotate;//CGAffineTransformConcat(translate, rotate);
[gesture setTranslation:CGPointMake(0, 0) inView:self.view];
} else if (gesture.state == UIGestureRecognizerStateEnded){
// Animate snap back to place
[UIView animateWithDuration:0.2 animations:^{
gesture.view.transform = CGAffineTransformIdentity;
// [self.imagePost setCenter:point];
}];
}
}
Try adding this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (![gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] && ![otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
return YES;
}
return NO;
}

Reset UIView's frame with a pan gesture without hardcoding start values

I have a UIPanGestureRecognizer that is attached to a UIView. What I am trying to do is essentially drag and drop into a bucket. If the user lets go of the UIView and it's not in the bucket, I want it to animate back to its original start location. My selector that gets called for my UIPanGestureRecognizer is:
- (void)handleDragDescriptionView:(UIPanGestureRecognizer *)gestureRecognizer {
UIView *panViewPiece = [gestureRecognizer view];
CGRect originalFrame = CGRectMake(946, 20, 58, 30);
CGPoint translation = [gestureRecognizer translationInView:panViewPiece];
if (gestureRecognizer.state == UIGestureRecognizerStateBegan || gestureRecognizer.state == UIGestureRecognizerStateChanged) {
panViewPiece.center = CGPointMake(panViewPiece.center.x + translation.x, panViewPiece.center.y + translation.y);
[gestureRecognizer setTranslation:CGPointZero inView:panViewPiece.superview];
}
else if (gestureRecognizer.state == UIGestureRecognizerStateCancelled) {
[UIView animateWithDuration:0.25 animations:^{
self.dragDescriptionView.frame = originalFrame;
}];
}
else {
[UIView animateWithDuration:0.25 animations:^{
self.dragDescriptionView.frame = originalFrame;
}];
}
}
I was wondering if I could do this without the originalFrame at the top of the method. I originally had
CGRect originalFrame = _dragDescriptionView.frame;
instead of the hardcoding, but it doesn't snap back. Probably because I'm updating that value as I am dragging. I don't particularly like hardcoding values, but I wasn't sure if there was a way around this. Thanks!
You really only need to track the view's original center. Make originalCenter an instance variable and only set it when the gesture begins:
#implementation MyViewController {
CGPoint _originalCenter;
}
- (void)handleDragDescriptionView:(UIPanGestureRecognizer *)gestureRecognizer {
UIView *panViewPiece = [gestureRecognizer view];
switch (gestureRecognizer.state) {
case UIGestureRecognizerStateBegan:
_originalCenter = panViewPiece.center;
break;
case UIGestureRecognizerStateChanged: {
CGPoint translation = [gestureRecognizer translationInView:panViewPiece.superview];
panViewPiece.center = CGPointMake(panViewPiece.center.x + translation.x, panViewPiece.center.y + translation.y);
[gestureRecognizer setTranslation:CGPointZero inView:panViewPiece.superview];
break;
}
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled: {
[UIView animateWithDuration:0.25 animations:^{
panViewPiece.center = _originalCenter;
}];
break;
}
default:
break;
}
}

Resources