How to Zoom In/Out Photo on double Tap in the iPho

2019-01-21 03:21发布

问题:

I am going through the Sample code of iPhone WWDC 2010 - 104 PhotoScroller App. It's working great with my project related images (PDF Page Images)

but I am struggling detect touches in the PhotoScroller App. The Zooming using multiple touches is handled by the ScrollVoiew. Now I want to Zoom In/out the photo on double Tap. The Touchesbegan method is being called in TilingView Class. Then I used [super touchesbegan: withevent:] and now the touches are in the ImageScrollView Class.

How to get these touch events in PhotoViewController. How to achieve the zoom in and zoom out on touch ?

Can anyone help in this Regard ?

回答1:

I researched several different web sites and I came up with the following...

Place this code into your viewDidLoad or viewWillAppear method:

//////////////////////////////
// Listen for Double Tap Zoom

UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];

[doubleTap setNumberOfTapsRequired:2];

[self.scrollView addGestureRecognizer:doubleTap];

[doubleTap release];

Add this to your header file:

- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer;

Add this to your implementation:

- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {  

    if(self.scrollView.zoomScale > self.scrollView.minimumZoomScale)
        [self.scrollView setZoomScale:self.scrollView.minimumZoomScale animated:YES]; 
    else 
        [self.scrollView setZoomScale:self.scrollView.maximumZoomScale animated:YES]; 

  }  

Currently this does not center upon the area where the user double tapped.



回答2:

My code, based upon some of the code at link "UIImageView does not zoom" This code handles toggling between zoomed in and zoomed out and will allow detection of a single tap along with a double tap. It also properly centers the zoom on the embedded image by applying the view transform on it. This code would go in the ImageScrollView class from the sample code.

- (void)setupGestureRecognisers:(UIView *)viewToAttach {

    UITapGestureRecognizer *dblRecognizer;
    dblRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                        action:@selector(handleDoubleTapFrom:)];
    [dblRecognizer setNumberOfTapsRequired:2];

    [viewToAttach addGestureRecognizer:dblRecognizer];
    self.doubleTapRecognizer = dblRecognizer;

    UITapGestureRecognizer *recognizer;
    recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                     action:@selector(handleTapFrom:)];
    [recognizer requireGestureRecognizerToFail:dblRecognizer];

    [viewToAttach addGestureRecognizer:recognizer];
    self.tapRecognizer = recognizer;
}

- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer {

   // do your single tap
}


- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {

    CGRect zoomRect;

    zoomRect.size.height = [_imageView frame].size.height / scale;
    zoomRect.size.width  = [_imageView frame].size.width  / scale;

    center = [_imageView convertPoint:center fromView:self];

    zoomRect.origin.x    = center.x - ((zoomRect.size.width / 2.0));
    zoomRect.origin.y    = center.y - ((zoomRect.size.height / 2.0));

    return zoomRect;
}

- (void)handleDoubleTapFrom:(UITapGestureRecognizer *)recognizer {

    float newScale = [self zoomScale] * 4.0;

    if (self.zoomScale > self.minimumZoomScale)
    {
        [self setZoomScale:self.minimumZoomScale animated:YES]; 
    }
    else 
    {
        CGRect zoomRect = [self zoomRectForScale:newScale 
                                   withCenter:[recognizer locationInView:recognizer.view]];
        [self zoomToRect:zoomRect animated:YES];
    }
}


回答3:

Here is a Swift solution based on @possen's great answer.
- Put this in your view controller that contains the scrollview and is the scrollview delegate.
- This solution is great since it actually zooms to the tap location:

@IBAction func handleDoubleTapScrollView(recognizer: UITapGestureRecognizer) {
    if scrollView.zoomScale == 1 {
        scrollView.zoom(to: zoomRectForScale(scale: scrollView.maximumZoomScale, center: recognizer.location(in: recognizer.view)), animated: true)
    } else {
        scrollView.setZoomScale(1, animated: true)
    }
}

func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
    var zoomRect = CGRect.zero
    zoomRect.size.height = imageView.frame.size.height / scale
    zoomRect.size.width  = imageView.frame.size.width  / scale
    let newCenter = scrollView.convert(center, from: imageView)
    zoomRect.origin.x = newCenter.x - (zoomRect.size.width / 2.0)
    zoomRect.origin.y = newCenter.y - (zoomRect.size.height / 2.0)
    return zoomRect
}


回答4:

I combined the answers from @jayesh kavathiya and @possen into a single implementation which works pretty well, as long as you've set appropriate values for self.minimumZoomScale and self.maximumZoomScale.

- (void)doubleTap:(UITapGestureRecognizer*)recognizer
{
    if (self.zoomScale > self.minimumZoomScale)
    {
        [self setZoomScale:self.minimumZoomScale animated:YES];
    }
    else
    {
        CGPoint touch = [recognizer locationInView:recognizer.view];

        CGSize scrollViewSize = self.bounds.size;

        CGFloat w = scrollViewSize.width / self.maximumZoomScale;
        CGFloat h = scrollViewSize.height / self.maximumZoomScale;
        CGFloat x = touch.x-(w/2.0);
        CGFloat y = touch.y-(h/2.0);

        CGRect rectTozoom=CGRectMake(x, y, w, h);
        [self zoomToRect:rectTozoom animated:YES];
    }
}


回答5:

Swift 3

Normally image zoom functionality is required with both double tap and pinch gesture, so I am providing complete solution to achieve the same. Double tap zoom is inspired by above answers and pinch zoom was taken from here.

import UIKit

class ViewController: UIViewController, UIScrollViewDelegate {

    var imageView: UIImageView!
    var scrollImg: UIScrollView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let vWidth = self.view.frame.width
        let vHeight = self.view.frame.height

        scrollImg = UIScrollView()
        scrollImg.delegate = self
        scrollImg.frame = CGRect(x: 0, y: 0, width: vWidth, height: vHeight)
        scrollImg.backgroundColor = UIColor(red: 90, green: 90, blue: 90, alpha: 0.90)
        scrollImg.alwaysBounceVertical = false
        scrollImg.alwaysBounceHorizontal = false
        scrollImg.showsVerticalScrollIndicator = true
        scrollImg.flashScrollIndicators()

        scrollImg.minimumZoomScale = 1.0
        scrollImg.maximumZoomScale = 10.0

        let doubleTapGest = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTapScrollView(recognizer:)))
        doubleTapGest.numberOfTapsRequired = 2
        scrollImg.addGestureRecognizer(doubleTapGest)

        self.view.addSubview(scrollImg)

        imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: vWidth, height: vHeight))
        imageView.image = UIImage(named: "cat")
        imageView!.layer.cornerRadius = 11.0
        imageView!.clipsToBounds = false
        scrollImg.addSubview(imageView!)
    }

    func handleDoubleTapScrollView(recognizer: UITapGestureRecognizer) {
        if scrollImg.zoomScale == 1 {
            scrollImg.zoom(to: zoomRectForScale(scale: scrollImg.maximumZoomScale, center: recognizer.location(in: recognizer.view)), animated: true)
        } else {
            scrollImg.setZoomScale(1, animated: true)
        }
    }

    func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
        var zoomRect = CGRect.zero
        zoomRect.size.height = imageView.frame.size.height / scale
        zoomRect.size.width  = imageView.frame.size.width  / scale
        let newCenter = imageView.convert(center, from: scrollImg)
        zoomRect.origin.x = newCenter.x - (zoomRect.size.width / 2.0)
        zoomRect.origin.y = newCenter.y - (zoomRect.size.height / 2.0)
        return zoomRect
    }

    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return self.imageView
    }

}


回答6:

use this code so it will zoom where you click.......

- (void)handleDoubleTap:(UIGestureRecognizer *)recognizer {  
        if(zoomCheck){
            CGPoint Pointview=[recognizer locationInView:self];
            CGFloat newZoomscal=3.0;

            newZoomscal=MIN(newZoomscal, self.maximumZoomScale);

            CGSize scrollViewSize=self.bounds.size;

            CGFloat w=scrollViewSize.width/newZoomscal;
            CGFloat h=scrollViewSize.height /newZoomscal;
            CGFloat x= Pointview.x-(w/2.0);
            CGFloat y = Pointview.y-(h/2.0);

            CGRect rectTozoom=CGRectMake(x, y, w, h);
            [self zoomToRect:rectTozoom animated:YES]; 

            [self setZoomScale:3.0 animated:YES]; 
            zoomCheck=NO;
        }
        else{ 
            [self setZoomScale:1.0 animated:YES]; 
            zoomCheck=YES;
        }
    } 

use this code so it will zoom where you click....... zoomChech is bool variable for checking zoom



回答7:

Previous answer could be simpler with BlocksKit, like below.

#import "BlocksKit.h"
...
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithHandler:^(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) {
    if(scrollView.zoomScale != 1.0){
        [scrollView setZoomScale:1.0 animated:YES];
    }else{
        [scrollView setZoomScale:2.0 animated:YES];
    }
}];
[doubleTap setNumberOfTapsRequired:2];
[scrollView addGestureRecognizer:doubleTap];


回答8:

How about adding a UITapGestureRecognizer to the ImageScrollView?

As long as you are looking at sample code, you can check out how UIGestureRecognizers are used in the ScrollViewSuite sample code.



回答9:

Subclass the UIScrollView an in m file add

#pragma mark -
#pragma mark doubleTouch

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    NSUInteger tapCount = [touch tapCount];
    switch (tapCount) {
        case 2:
        {
            if(self.zoomScale <1.0){
                [self setZoomScale:1.0 animated:YES];
            }else{
                [self setZoomScale:0.1 animated:YES];
            }

            break;
        }
        default:
            break;
    }
}


回答10:

This appears to work using convertRect:fromView: and zoomToRect:animated::

-(void)tap:(UITapGestureRecognizer *)tapGestureRecognizer
{
    CGFloat zoomeScaleMultiplier = 0.5;
    UIScrollView *scrollView = (UIScrollView *) tapGestureRecognizer.view;
    UIView *zoomableView = [scrollView.delegate viewForZoomingInScrollView:scrollView];

    CGRect rect = scrollView.bounds;
    rect.origin = CGPointZero;

    CGAffineTransform transform = CGAffineTransformMakeScale(zoomeScaleMultiplier, zoomeScaleMultiplier);
    rect = CGRectApplyAffineTransform(rect, transform);

    rect.origin = [tapGestureRecognizer locationInView:scrollView];

    rect = CGRectOffset(rect, CGRectGetWidth(rect)/-2., CGRectGetHeight(rect)/-2.);

    rect = [zoomableView convertRect:rect fromView:scrollView];

    [scrollView zoomToRect:rect animated:YES];
}


回答11:

Zooms in on tap location

CGFloat scale = 3.0;
CGFloat scale = ScaleToAspectFitRectAroundRect(frame, self.bounds) * 2.0;

CGRect zoomRect;
CGPoint point = [gestureRecognizer locationOfTouch:0 inView:[gestureRecognizer view]];

zoomRect.size.height = frame.size.height * scale;
zoomRect.size.width  = frame.size.width  * scale;

zoomRect.origin.x = CGRectGetMidX(frame) - (CGRectGetWidth(zoomRect)/2) + (scale * (CGRectGetWidth(frame)/2 - point.x)) - (CGRectGetWidth(frame)/2 - point.x);
zoomRect.origin.y = CGRectGetMidY(frame) - (CGRectGetHeight(zoomRect)/2) + (scale * (CGRectGetHeight(frame)/2 - point.y)) - (CGRectGetHeight(frame)/2 - point.y);


回答12:

You will need to implement viewForZooming(in scrollView: UIScrollView) -> UIView? in UIScrollViewDelegate in order to get @n8tr's answer working.

So the complete code will look something like this

class ViewController: UIViewController, UIScrollViewDelegate {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var imageView: UIImageView!


    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.delegate = self
    }

    @IBAction func handleDoubleTapScrollView(recognizer: UITapGestureRecognizer) {
        if scrollView.zoomScale == 1 {
            scrollView.zoom(to: zoomRectForScale(scale: scrollView.maximumZoomScale, center: recognizer.location(in: recognizer.view)), animated: true)
        } else {
            scrollView.setZoomScale(1, animated: true)
        }
    }

    func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
        var zoomRect = CGRect.zero
        zoomRect.size.height = imageView.frame.size.height / scale
        zoomRect.size.width  = imageView.frame.size.width  / scale
        let newCenter = imageView.convert(center, from: scrollView)
        zoomRect.origin.x = newCenter.x - (zoomRect.size.width / 2.0)
        zoomRect.origin.y = newCenter.y - (zoomRect.size.height / 2.0)
        return zoomRect
    }


    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
}


回答13:

here my code work for me it's simple :

// Listen for Double Tap Zoom
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];

[doubleTap setNumberOfTapsRequired:2];

[self addGestureRecognizer:doubleTap];

you need

BOOL checkZoomImage;

Here tab method

- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {

    if (self.zoomScale > self.minimumZoomScale && self.zoomScale == self.maximumZoomScale){
        checkZoomImage = YES;
    }
    if (self.zoomScale < self.maximumZoomScale && self.zoomScale == self.minimumZoomScale) {
        checkZoomImage = NO;
    }


    if (checkZoomImage) {
        [self setZoomScale:self.zoomScale *0.5 animated:YES];
    }else{
        [self setZoomScale:self.zoomScale *1.5 animated:YES];
    }

}