10

I have a image in iOS. I have added pinch gesture on the image when i pinch the image it shifted to top left corner. I have also added pan gesture on image. When an image is zoomed then i am scrolling the image in every direction for that purpose i have added the pan gesture into the image.

My code is :

-(void)viewDidLoad
{
UIPinchGestureRecognizer *pinch=[[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
            [self.zoom_image addGestureRecognizer:pinch];
            panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveImage:)];
            [panGesture setMinimumNumberOfTouches:1];
            [panGesture setMaximumNumberOfTouches:1];
            [self.zoom_image addGestureRecognizer:panGesture];

            img_center_x = self.zoom_image.center.x;
            img_center_y = self.zoom_image.center.y;

}

-(void)handlePinch:(UIPinchGestureRecognizer*)sender
{
    NSLog(@"latscale = %f",mLastScale);
    mCurrentScale += [sender scale] - mLastScale;
    mLastScale = [sender scale];
    NSLog(@"before ceneter x %f",img_center_x);
    NSLog(@"before ceneter x %f",img_center_y);
    CGPoint img_center = CGPointMake(img_center_x, img_center_y);
    self.zoom_image.center = img_center;
    if (sender.state == UIGestureRecognizerStateEnded)
    {
      mLastScale = 1.0;
    }
    if(mCurrentScale<1.0)
    {
        mCurrentScale=1.0;
    }
    if(mCurrentScale>3.0)
    {
        mCurrentScale=3.0;
    }
    CGAffineTransform currentTransform = CGAffineTransformIdentity;
    CGAffineTransform newTransform = CGAffineTransformScale(currentTransform,mCurrentScale, mCurrentScale);
    self.zoom_image.transform = newTransform;

}

Pan gesture

 UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveImage:)];
            [panGesture setMinimumNumberOfTouches:1];
            [panGesture setMaximumNumberOfTouches:1];
            [self.zoom_image addGestureRecognizer:panGesture];

move image:

- (void)moveImage:(UIPanGestureRecognizer *)recognizer
{
    CGPoint translation = [recognizer translationInView:self.zoom_image];
    CGPoint location = [recognizer locationInView:self.view];
    CGPoint initial=CGPointZero;
    NSLog(@"%f\n%f",translation.x,translation.y);
    NSLog(@"%f",self.zoom_image.frame.origin.y);
    CGPoint finalpoint = CGPointMake(self.zoom_image.center.x + translation.x, self.zoom_image.center.y+ translation.y);
    NSLog(@"%f",finalpoint.y);
    //limit the boundary
    if(recognizer.state==UIGestureRecognizerStateChanged)
    {
        if ((self.zoom_image.frame.origin.x>0 && translation.x > 0) || (self.zoom_image.frame.origin.x + self.zoom_image.frame.size.width<=self.view.frame.size.width && translation.x < 0))
            finalpoint.x = self.zoom_image.center.x;

        if ((self.zoom_image.frame.origin.y>100 && translation.y > 0) || (self.zoom_image.frame.origin.y + self.zoom_image.frame.size.height<=self.view.frame.size.height && translation.y < 0))
            finalpoint.y = self.zoom_image.center.y;
        //set final position
        NSLog(@"%f",finalpoint.y);
        self.zoom_image.center = finalpoint;
        [recognizer setTranslation:initial inView:self.zoom_image];
    }
}
Nik
  • 1,679
  • 1
  • 20
  • 36
TechChain
  • 8,404
  • 29
  • 103
  • 228

1 Answers1

0

Here is a possible solution.

• I've renamed your zoom_image by contentView, because this class can manipulate any view, not only images.

• I've removed the bound tests, and let the scale be in ( 0.01 - 10.0 )

• The pinch handle up to three fingers, and also acts as pan. Number of touches can be changed without interrupting the pinch.

There is still many things to improve, but the main principle is here :)

Interface ( properties like minScale,maxScale, minMargin and so are still to be added - why not a delegate )

@interface PinchViewController : UIViewController

@property(nonatomic,strong) IBOutlet UIView* contentView;

@end

Implementation

@implementation PinchViewController
{
    CGPoint translation;
    CGFloat scale;

    CGAffineTransform scaleTransform;
    CGAffineTransform translateTransform;

    CGPoint     previousTranslation;
    CGFloat     previousScale;
    NSUInteger  previousNumTouches;
}

-(void)viewDidLoad
{
    scale = 1.0f;
    scaleTransform = CGAffineTransformIdentity;
    translateTransform = CGAffineTransformIdentity;
    previousTranslation = CGPointZero;
    previousNumTouches = 0;

    UIPinchGestureRecognizer *pinch=[[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
    [self.view addGestureRecognizer:pinch];

    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [panGesture setMinimumNumberOfTouches:1];
    [panGesture setMaximumNumberOfTouches:1];
    [self.view addGestureRecognizer:panGesture];

}

-(void)handlePinch:(UIPinchGestureRecognizer*)recognizer
{
    // 1 - find pinch center
    CGPoint mid = [self computePinchCenter:recognizer];
    mid.x-= recognizer.view.bounds.size.width / 2.0f;
    mid.y-= recognizer.view.bounds.size.height / 2.0f;

    // 2 - compute deltas
    NSUInteger numTouches = recognizer.numberOfTouches;
    if ( (recognizer.state==UIGestureRecognizerStateBegan)  || ( previousNumTouches != numTouches ) ) {
        previousScale = recognizer.scale;
        previousTranslation = mid;
        previousNumTouches = numTouches;
    }

    CGFloat deltaScale = ( recognizer.scale - previousScale ) * scale;
    previousScale = recognizer.scale;

    CGPoint deltaTranslation = CGPointMake(mid.x-previousTranslation.x, mid.y-previousTranslation.y);
    previousTranslation = mid;

    deltaTranslation.x/=scale;
    deltaTranslation.y/=scale;

    // 3 - apply
    scale+=deltaScale;

    if (scale<0.01) scale = 0.01; else if (scale>10) scale = 10;

    scaleTransform = CGAffineTransformMakeScale(scale, scale);
    [self translateBy:deltaTranslation];

    NSLog(@"Translation : %.2f,%.2f - Scale Center : %.2f,%.2f - Scale : %.2f",deltaTranslation.x,deltaTranslation.y,mid.x,mid.y,scale);
}

- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
    if (recognizer.state==UIGestureRecognizerStateBegan) previousTranslation = CGPointZero;
    CGPoint recognizerTranslation = [recognizer translationInView:self.contentView];
    CGPoint deltaTranslation = CGPointMake(recognizerTranslation.x - previousTranslation.x,recognizerTranslation.y - previousTranslation.y);
    previousTranslation = recognizerTranslation;
    [self translateBy:deltaTranslation];

    NSLog(@"Translation : %.2f,%.2f - Scale : %.2f",deltaTranslation.x,deltaTranslation.y,scale);
}


-(void)translateBy:(CGPoint)delta
{
    translation.x+=delta.x;
    translation.y+=delta.y;
    translateTransform = CGAffineTransformMakeTranslation(translation.x,translation.y);
    self.contentView.transform = CGAffineTransformConcat(translateTransform,scaleTransform);
}

-(CGPoint)computePinchCenter:(UIPinchGestureRecognizer*)recognizer
{
    // 1 - handle up to 3 touches
    NSUInteger numTouches = recognizer.numberOfTouches;
    if (numTouches>3) numTouches = 3;

    // 2 - Find fingers middle point - with (0,0) being the center of the view
    CGPoint pt1,pt2,pt3,mid;
    switch (numTouches) {
        case 3:
            pt3 = [recognizer locationOfTouch:2 inView:recognizer.view];
        case 2:
            pt2 = [recognizer locationOfTouch:1 inView:recognizer.view];
        case 1:
            pt1 = [recognizer locationOfTouch:0 inView:recognizer.view];
    }
    switch (numTouches) {
        case 3:
            mid = CGPointMake( ( ( pt1.x + pt2.x ) / 2.0f + pt3.x ) / 2.0f, ( ( pt1.y + pt2.y ) / 2.0f + pt3.y ) / 2.0f );
            break;
        case 2:
            mid = CGPointMake( ( pt1.x + pt2.x ) / 2.0f, ( pt1.y + pt2.y ) / 2.0f  );
            break;
        case 1:
            mid = CGPointMake( pt1.x, pt1.y);
            break;
    }
    return mid;
}

@end

Hope it will help :) Cheers

Moose
  • 2,607
  • 24
  • 23
  • right… That was a quick guess. I've slept on it. I edit and replace by a possible way to do it. – Moose Nov 07 '15 at 08:31
  • Yep - first solution was a quick guess, not working. The edited answer works, and still allow a lot of improvements. – Moose Nov 07 '15 at 08:45
  • what kind of improvements? – TechChain Nov 07 '15 at 08:47
  • set the limits with properties like minScale, maxScale… The pinch algorithm works already quite well, but the center of the fingers is not totally still while scaling. It should, but I can't spend more time on it :) – Moose Nov 07 '15 at 08:50
  • By the way, I vote your question up, because that was an interesting challenge ;) See ya ! – Moose Nov 07 '15 at 08:52
  • Voting up was much more easy than writing a working code to answer you @deepakkumar... – Moose Nov 09 '15 at 10:27
  • You should have told it before… In facts, it works very well. I've tested it on iPhone 5 iOS 9.x and iPad iOS 8.x - Try the project : https://drive.google.com/open?id=0B88aMtNA0z2aWVBIbGZGdVhpdWM – Moose Nov 09 '15 at 11:47
  • it moves the image even the image is not zoomed.So plaease tell why – TechChain Nov 09 '15 at 11:54
  • I tell you why. The image does not move when it size is inferior to the screen size. In this case it is centered. If the image is bigger, you can move it, even if scale is one. But you are on stackoverflow, which is a collaborative platform. We are not suppose to offer you a finished product, even for a bounty ( that you don't give ) but to propose you the best possible clue to achieve your goal. If you prefer the image to be unmovable when scale is one, even if it is bigger than the screen, adapt it to your needs. The base is correct. – Moose Nov 09 '15 at 12:01
  • Just add a if (scale<=0.0f) return; at the beginning of the translateBy method to block translation when scale is inferior to 1 – Moose Nov 09 '15 at 12:18
  • Have you downloaded my sample project ? I did not send you something that does not work. I told you it has been tested on two devices. – Moose Nov 10 '15 at 07:13
  • your google drive code need access.so please make it public.I am not abe to download it – TechChain Nov 10 '15 at 07:16
  • Sorry ;) - https://drive.google.com/file/d/0B88aMtNA0z2aWVBIbGZGdVhpdWM/view?usp=sharing – Moose Nov 10 '15 at 07:34
  • This works but i am able to zoom out into minimum level which should not happen – TechChain Nov 10 '15 at 07:55
  • Just change the limits. I also told you it can be improved. Simply change the line " if (scale<0.01) scale = 0.01; else if (scale>10) scale = 10;" to modify the limits... – Moose Nov 10 '15 at 08:04
  • This is a working basis. From there you must be able to adapt it to your needs without big changes. – Moose Nov 10 '15 at 08:05
  • It is in the code I sent you, in the handlePinch method. You can set all pinch behavior in handlePinch method, and all translate behavior in the translateBy method - Not in the handlePan method, because when you pinch, you can also pan the image. – Moose Nov 10 '15 at 08:27
  • Please post the exact code for overcome this behaviour.I am not able to understand – TechChain Nov 10 '15 at 08:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/94683/discussion-between-moose-and-deepak-kumar). – Moose Nov 10 '15 at 08:34