如何在iPhone WWDC 2010-104 PhotoScroller上通过双击进行照片缩放

44
我正在研究iPhone WWDC 2010 - 104 PhotoScroller应用程序的示例代码。 它与我的项目相关图像(PDF页面图像)很好地配合使用。
但是我正在努力在PhotoScroller App中检测触摸。使用多点触摸进行缩放由ScrollVoiew处理。现在我想双击放大/缩小照片。Touchesbegan方法在TilingView类中被调用。然后我使用[super touchesbegan:withevent:],现在触摸事件在ImageScrollView类中。
如何在PhotoViewController中获取这些触摸事件? 如何通过触摸实现缩放?
有人能帮忙吗?

你不应该已经接受一个回答吗? - Radu Simionescu
14个回答

71

我调查了几个不同的网站,得到了以下结果...

将此代码放入您的viewDidLoad或viewWillAppear方法中:

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

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

[doubleTap setNumberOfTapsRequired:2];

[self.scrollView addGestureRecognizer:doubleTap];

[doubleTap release];

将这段代码添加到您的头文件中:

- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer;
将以下内容添加到你的实现中:
- (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]; 

  }  

目前这个功能不能将焦点置于用户双击的区域中心。


这对我不起作用(IOS新手)。我应该将其放到控制xib操作的视图文件中,还是需要创建一个自定义滚动视图类? - Dnaso

65

我的代码是基于链接“UIImageView does not zoom”中的一些代码编写的。该代码处理放大和缩小之间的切换,并允许检测单击和双击。它还通过在图像上应用视图变换来正确地将缩放居中于嵌入式图像上。此代码应放置在示例代码中的ImageScrollView类中。

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

这是最好的解决方案,因为它实际上会缩放到触摸位置。我在下面包含了一个基于此的 Swift 版本。 - n8tr
感谢提供快速版本! - possen

40

以下是基于@possen的出色答案的Swift解决方案。
- 将此代码放入包含滚动视图并且是滚动视图委托的视图控制器中。
- 这个解决方案非常棒,因为它实际上会缩放到点击位置:

@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
}

你确定吗?我在App Store上的hashpic应用中有这段代码。不过可能需要更新为Swift 3。 - n8tr
4
目前来看,这份代码是无法运行的。convert(:from:) 的调用应该更改为 convert(:to:),或者交换该行中的 scrollView 和 imageView。根据文档,“矩形应该在由 viewForZooming(in:) 返回的视图的坐标空间中”,而在这种情况下,该视图是 imageView。在 Pavel Vavilov 编辑之前是正确的。我已经提交了一份修正该问题的编辑建议。 - Shadowfacts
完全同意@Shadowfacts的观点 - convert(:from:)调用必须更改为convert(:to:),这样才能正常工作。 - A. Poltoratskyi

21

Swift 3

通常情况下,图像缩放功能需要用双击和捏合手势来实现,因此我提供了完整的解决方案来实现这一点。双击缩放受到上面答案的启发,而捏合缩放则来自这里

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
    }

}

16

我将 @jayesh kavathiya 和 @possen 的答案结合起来,形成了一个单一的实现,只要您设置了适当的 self.minimumZoomScaleself.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];
    }
}

3
请使用以下代码,它可以在您单击时进行缩放......
- (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;
        }
    } 

使用此代码,它将在您单击的位置进行缩放...... zoomCheck是用于检查缩放的布尔变量。

这太棒了。如果你使用 @possen 的 if-else 条件语句,那就更好了! - Ricardo RendonCepeda

3

这是使用 Swift 5 编写的最新捏合缩放和双击缩放代码。

import UIKit

class ViewController: UIViewController, UIScrollViewDelegate {

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

override func viewDidLoad() {
    super.viewDidLoad()
    scrollView.delegate = self

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

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

@objc 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
}


}

我附上了故事板图片。 enter image description here

1
你好,你要如何更改代码以使其以相同的方式进行缩放:我是指增量到点击位置,即,如果您将else语句更改为以下内容:scrollView.zoom(to: zoomRectForScale(scale: scrollView.zoomScale*2, center: recognizer.location(in: recognizer.view)), animated: true) - Stéphane de Luca

2
您需要在UIScrollViewDelegate中实现viewForZooming(in scrollView: UIScrollView) -> UIView?才能使@n8tr的答案起作用。

enter image description here

所以完整的代码将看起来像这样。
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
    }
}

2

使用 BlocksKit 可以更简单地实现前面的答案,代码如下。

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

4
似乎你应该能够在没有任何第三方代码的情况下完成所有这些操作,对吗? - Kyle Clegg

1

在ImageScrollView中添加一个UITapGestureRecognizer怎么样?

只要你查看示例代码,就可以了解如何在 ScrollViewSuite示例代码中使用UIGestureRecognizers。


谢谢回复。我将尝试使用UITapGestureRecognizer;但是UITapGestureRecognizer仅支持iOS 3.2及以上版本。如何在iPhone 3.0中实现上述功能? - Roger_iPhone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接