【问题标题】:How to Zoom In/Out Photo on double Tap in the iPhone WWDC 2010 - 104 PhotoScroller如何在 iPhone WWDC 2010 - 104 PhotoScroller 中双击放大/缩小照片
【发布时间】:2011-04-27 10:44:20
【问题描述】:

我正在浏览 iPhone WWDC 2010 - 104 PhotoScroller App 的示例代码。 它与我的项目相关图像(PDF 页面图像)效果很好

但我正在努力检测 PhotoScroller 应用程序中的触摸。使用多个触摸的缩放由 ScrollVoiew 处理。现在我想在双击时放大/缩小照片。在 TilingView 类中调用 Touchesbegan 方法。然后我使用 [super touchesbegan: withevent:] 现在触摸在 ImageScrollView 类中。

如何在 PhotoViewController 中获取这些触摸事件。 如何实现触摸放大和缩小?

任何人都可以在这方面提供帮助吗?

【问题讨论】:

  • 你不应该已经接受答案了吗?

标签: iphone uiscrollview uitouch touchesbegan wwdc


【解决方案1】:

我研究了几个不同的网站,我想出了以下...

将此代码放入您的 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 noob)。我是把它放在我控制 xib 操作的视图文件中还是我需要创建一个自定义的 scoll 视图类?
【解决方案2】:

我的代码,基于链接“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 版本。
  • 感谢快速版本!
【解决方案3】:

这是一个基于 @possen's 很好的答案的 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 进行更新。
  • 按原样,这是行不通的。 convert(:from:) 调用应更改为 convert(:to:) 或该行上的 scrollView 和 imageView 应交换。根据文档,“矩形应该在 viewForZooming(in:) 返回的视图的坐标空间中”,在这种情况下是 imageView。在 Pavel Vavilov 的编辑之前是正确的。我已提交修正此问题的修改。
  • 完全同意@Shadowfacts - convert(:from:) 调用必须更改为 convert(:to:),这样才能正常工作。
【解决方案4】:

斯威夫特 3

双击和捏合手势通常都需要图像缩放功能,因此我提供了完整的解决方案来实现相同的功能。双击缩放受上述答案的启发,捏缩放取自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
    }

}

【讨论】:

    【解决方案5】:

    只要您为self.minimumZoomScaleself.maximumZoomScale 设置了适当的值,我将@jayesh kavathiya 和@possen 的答案组合成一个运行良好的单一实现。

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

    【讨论】:

      【解决方案6】:

      使用这个代码,它会在你点击的地方放大......

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

      使用这个代码,它会在你点击的地方放大...... zoomChech 是用于检查缩放的布尔变量

      【讨论】:

      • 这太棒了。如果您使用@possen 答案中的 if-else 条件,那就更好了!
      【解决方案7】:

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

      【讨论】:

      • 看起来你应该能够在没有任何第三方代码的情况下完成所有这些,不是吗?
      【解决方案8】:

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

      所以完整的代码看起来像这样

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

      【讨论】:

        【解决方案9】:

        这是最新的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
        }
        
        
        }
        

        我也附上了故事板图片。

        【讨论】:

        • 嗨,你将如何改变以使其以相同的方式放大/缩小:我的意思是增量到录音位置,即,如果你按如下方式制作 else:scrollView.zoom(to: zoomRectForScale(scale: scrollView.zoomScale*2, center: recognizer.location(in: recognizer.view)), animated: true) }
        【解决方案10】:

        给 ImageScrollView 添加一个 UITapGestureRecognizer 怎么样?

        只要你在看示例代码,你就可以在ScrollViewSuite sample code中查看UIGestureRecognizers是如何使用的。

        【讨论】:

        • 感谢回复我会尝试使用UITapGestureRecognizer;但 iOS 3.2 及更高版本支持 UITapGestureRecognizer。如何在 iPhone 3.0 中实现上述功能?
        【解决方案11】:

        子类化 UIScrollView 并在 m 文件中添加

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

        【讨论】:

          【解决方案12】:

          这似乎可以使用 convertRect:fromView: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];
          }
          

          【讨论】:

            【解决方案13】:

            点击位置放大

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

            【讨论】:

              【解决方案14】:

              我的代码对我来说很简单:

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

              你需要

              BOOL checkZoomImage;
              

              这里选项卡方法

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

              【讨论】:

              • 你的意思是双击?还是单击?
              • 双击。您的代码只是在双击时放大,而不需要注意计算它被点击的区域,然后调用 zoomToRect。
              猜你喜欢
              • 1970-01-01
              • 2011-04-20
              • 2017-10-27
              • 2018-04-09
              • 2012-02-19
              • 2017-10-13
              • 2011-05-23
              • 1970-01-01
              • 2011-06-29
              相关资源
              最近更新 更多