Search code examples
iphoneiosobjective-cuiscrollviewmwphotobrowser

Image dragging on a UIScrollView


A UIViewController is called when a user touches an image on a UITableViewCell. It is called using modalViewController. On this modalViewController is a UIScrollView, with another UIImageView in the middle, that fetches an image using NSDictionary (passed from the UITableViewCell).

Now, what I wanted to achieve was the ability for the user to drag the image vertically only, such that dragging and releasing a little would cause the image to return to the center with animation. If the user drags it to the extremes, the entire UIScrollView is dismissed and the user returns to the UITableView. I used the following code. The issue here is, and as my name suggests, this code is crude. Is there an elegant way of doing this, without the need of so much calculation?

BOOL imageMoved=NO;

- (void) touchesMoved:(NSSet *)touches
        withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
CGPoint pos = [touch locationInView: [UIApplication sharedApplication].keyWindow];

CGRect imageRect = _photoImageView.frame;//_photoImageView object of UIImageView
CGFloat imageHeight = imageRect.size.height;//getting height of the image
CGFloat imageTop=240-imageHeight/2;
CGFloat imageBottom=imageTop+imageHeight;//setting boundaries for getting coordinates of touch.
// Touches that originate above imageTop and below imageBottom are ignored(until touch reaches UIImageView)

if (pos.y>50&&pos.y<430&&pos.y>=imageTop&&pos.y<=imageBottom){//extremes are defined as top and bottom 50 pixels.
    imagedMoved=YES;//BOOL variable to hold if the image was dragged or not
    NSLog(@"%f", pos.y);
    [UIView setAnimationDelay:0];

    [UIView animateWithDuration:0.4

                     animations:^{_photoImageView.frame=CGRectMake(0,pos.y-imageHeight/2,320,200);}

                     completion:^(BOOL finished){ }];
}
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

UITouch * touch = [touches anyObject];
CGPoint pos = [touch locationInView: [UIApplication sharedApplication].keyWindow];

if (pos.y>50&&pos.y<430){//if touch has NOT ended in the extreme 50 pixels vertically
    [UIView setAnimationDelay:0];//restoring UIImageView to original center with animation

    [UIView animateWithDuration:0.4

                     animations:^{_photoImageView.frame=CGRectMake(0,140,320,200);}

                     completion:^(BOOL finished){ }];
imagedMoved=NO;//prepare BOOL value for next touch event
}

else if(pos.y<50||pos.y>430)
    if(imagedMoved)
    [self.photoBrowser exit] ;//exit function(imported from UIScrollViewController) dismisses
                  //modalView using [self dismissViewControllerAnimated:YES completion:nil];
}

All code here is a modification onto a customized copy of UITapView in MWPhotoBrowser.


Solution

  • Yo, here is a much easier way to do this, more or less an example of what Alessandro stated. I'm not finding the top of the screen but I'm giving the illusion of it.

    BCViewController.h

    #import <UIKit/UIKit.h>
    
    @interface BCViewController : UIViewController <UIScrollViewDelegate>
    @property (weak, nonatomic) IBOutlet UIScrollView *svScroller;
    @property (weak, nonatomic) IBOutlet UIImageView *ivFish;
    
    @end
    
    
    
    
    #import "BCViewController.h"
    
    @interface BCViewController (){
       UIPanGestureRecognizer *_panGestureRecognizer;
       CGPoint                 _fishOrigin;
    }
    
    @end
    
    @implementation BCViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
       self.svScroller.delegate = self;
       [self.svScroller setContentSize:self.view.frame.size];
       self.svScroller.translatesAutoresizingMaskIntoConstraints = NO;
       self.ivFish.userInteractionEnabled = YES;
    
       _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];
       [self.ivFish addGestureRecognizer:_panGestureRecognizer];
    
       _fishOrigin = self.ivFish.center;
    
       NSLog(@"center %f", self.ivFish.center.x);
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    -(void)handlePanFrom:(UIPanGestureRecognizer *)recognizer{
       // if you want it but not used
       CGPoint translation = [recognizer translationInView:recognizer.view];
       // if you want it but not used
       CGPoint velocity    = [recognizer velocityInView:recognizer.view];
       CGPoint tempPoint;
    
    
    if (recognizer.state == UIGestureRecognizerStateBegan) {
    
    } else if (recognizer.state == UIGestureRecognizerStateChanged) {
        tempPoint = [recognizer locationInView:self.view];
    
        self.ivFish.center = CGPointMake(175.5, tempPoint.y);
    
    } else if (recognizer.state == UIGestureRecognizerStateEnded) {
        CGPoint tempPoint;
        tempPoint = [recognizer locationInView:self.view];
    
        if (tempPoint.y < 132) {
            [UIView animateWithDuration:.3 delay:0
                                options:UIViewAnimationOptionCurveEaseOut
                             animations:^ {
                                 [self.navigationController popViewControllerAnimated:TRUE];
                             }
                             completion:NULL];
        } else {
            [UIView animateWithDuration:.3 delay:0
                                options:UIViewAnimationOptionCurveEaseOut
                             animations:^ {
                                 self.ivFish.center = _fishOrigin;
                             }
                             completion:NULL];
        }
    }
    }