【问题标题】:UIScrollView zoomToRect not zooming to given rect (created from UITouch CGPoint)UIScrollView zoomToRect 没有缩放到给定的矩形(从 UITouch CGPoint 创建)
【发布时间】:2011-01-23 23:00:34
【问题描述】:

我的应用程序有一个带有一个子视图的 UIScrollView。子视图是一个扩展的 UIView,它使用 drawLayer 事件中的图层将 PDF 页面打印到自身。

使用内置捏合进行缩放效果很好。 setZoomScale 也可以按预期工作。

我一直在努力使用 zoomToRect 函数。我在网上找到了一个示例,它从给定的 CGPoint 生成 CGRect zoomRect 变量。

在 touchesEnded 函数中,如果有一个双击并且它们一直被缩小,我想放大到我创建的 PDFUIView,就好像它们在他们双击的捏合中心进行捏合一样。

所以假设我将 UITouch 变量传递给我的函数,如果他们双击则使用 zoomToRect。

我从在苹果网站上找到的以下功能开始:

http://developer.apple.com/iphone/library/documentation/WindowsViews/Conceptual/UIScrollView_pg/ZoomZoom/ZoomZoom.html

以下是我的 UIScrollView 扩展类的修改版本:

- (void)zoomToCenter:(float)scale withCenter:(CGPoint)center {     

    CGRect zoomRect;
    zoomRect.size.height = self.frame.size.height / scale;
    zoomRect.size.width  = self.frame.size.width  / scale;

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

    //return zoomRect;

    [self zoomToRect:zoomRect animated:YES];

} 

当我这样做时,UIScrollView 似乎使用上方 zoomRect 的右下边缘而不是中心进行缩放。

如果我像这样制作 UIView

UIView *v = [[UIView alloc] initWithFrame:zoomRect]; 
[v setBackgroundColor:[UIView redColor]];
[self addSubview:v];

红色框出现,触摸点死在中心。

请注意:我是从我的 PC 上写这篇文章的,我记得我在我的 Mac 上弄乱了除以二的部分,所以假设这会在中心绘制一个触摸点的矩形。如果 UIView 偏离中心但缩放到正确的位置,那就太好了。

但是,当它执行 zoomToRect 时,它似乎使用了放大结果左上角 zoomRect 的右下角。

另外,我注意到根据我点击 UIScrollView 的位置,它会锚定到不同的位置。似乎中间有一个十字架,它以某种方式反射点,好像中间左边的任何地方都是负反射,中间的任何地方都是正反射?

这似乎很复杂,不应该只是缩放到 UIView 能够绘制的矩形吗?

我进行了大量研究来弄清楚如何创建高质量缩放的 PDF,所以我假设使用 CALayer 可能会脱离坐标系?但是对于 UIScrollView 来说,它应该将其视为具有 768x985 尺寸的视图。

这有点高级,请假设创建 zoomRect 的代码都很好。 UIScrollView 中的 UIView 中的 CALayer 有一些更深层次的东西......

【问题讨论】:

    标签: iphone uiscrollview calayer


    【解决方案1】:

    扩展 UIScrollView {

    func getRectForVisibleView() -> CGRect {
        var visibleRect: CGRect = .zero
        
        visibleRect.origin = self.contentOffset
        visibleRect.size = self.bounds.size
    
        let theScale = 1.0 / self.zoomScale
        visibleRect.origin.x *= theScale
        visibleRect.origin.y *= theScale
        visibleRect.size.width *= theScale
        visibleRect.size.height *= theScale
        
        return visibleRect
    }
    
    func moveToRect(rect: CGRect) {
        let scale = self.bounds.width / rect.width
        self.zoomScale = scale
        self.contentOffset = .init(x: rect.origin.x * scale, y: rect.origin.y * scale)
    }
    

    }

    【讨论】:

    • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票。
    【解决方案2】:
       Declare BOOL isZoom; in .h
    
    
         -(void)handleDoubleTap:(UIGestureRecognizer *)recognizer {  
                if(isZoom){
                    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]; 
                    isZoom=NO;
                }
                else{ 
                    [self setZoomScale:1.0 animated:YES]; 
                    isZoom=YES;
                }
            } 
    

    【讨论】:

      【解决方案3】:

      我不同意上面的一位 cmets 说你永远不应该将中心的坐标乘以某个因子。

      假设您当前在 100x100 滚动视图中显示整个 400x400 像素的图像或 PDF 文件,并希望允许用户将内容的大小翻倍,直到达到 1:1。 如果您双击点 (75,75),您希望放大的矩形在新的 200x200 内容视图中具有原点 100,100 和大小 100x100。所以原来的攻丝点 (75,75) 现在是 (150,150) 在新的 200x200 空间中。

      现在,在缩放操作 #1 完成后,如果您再次双击新的 100x100 矩形(即较大的 200x200 矩形的右下角)内的 (75,75),您希望用户显示了较大图像的右下角 100x100 正方形,现在将放大到 400x400 像素。

      为了计算这个最新的 100x100 矩形在较大的 400x400 矩形内的原点,您需要考虑比例和当前内容偏移(因为在最后一次缩放操作之前,我们在 200x200 内显示右下角的 100x100 矩形内容矩形)。

      所以最终矩形的 x 坐标变为: center.x/currentScale - (scrollView.frame.size.width/2) + scrollView.contentOffset.x/currentScale = 75/.5 - 100/2 + 100/.5 = 150 - 50 + 200 = 300。

      在这种情况下,作为正方形,y 坐标的计算是相同的。 我们确实放大了右下角的 100x100 矩形,在较大的 400x400 内容视图中,它的原点为 300,300。

      以下是计算缩放矩形的大小和原点的方法: zoomRect.size.height = mScrollView.frame.size.height/scale; zoomRect.size.width = mScrollView.frame.size.width/scale;

      zoomRect.origin.x = center.x/currentScale - (mScrollView.frame.size.width/2) + mScrollView.contentOffset.x/currentScale;
      zoomRect.origin.y = center.y/currentScale - (mScrollView.frame.size.height/2) + mScrollView.contentOffset.y/currentScale;
      

      希望这是有道理的;如果不画出各种正方形/矩形,就很难用书面形式来解释它。

      干杯, 拉夫·科拉桑特

      【讨论】:

        【解决方案4】:

        我尝试了不同的解决方案,但这看起来是最好的解决方案 它真的是直截了当和概念性的吗?

        CGRect frame = [[UIScreen mainScreen] applicationFrame];
        scrollView.contentInset = UIEdgeInsetsMake(frame.size.height/2,
                         frame.size.width/2,
                         frame.size.height/2,
                         frame.size.width/2); 
        

        【讨论】:

          【解决方案5】:

          好的,另一个答案:

          苹果提供的例程适用于我,但您需要让手势识别器将点击点转换为 imageView 坐标,而不是滚动条。

          Apple 的示例是这样做的,但是由于我们的应用程序工作方式不同(我们更改了 UIImageView),因此在 uiscrollview 上设置了 gestureRecongnizer - 工作正常,但您需要在 handleDoubleTap 中执行此操作:

          这大致基于苹果示例代码“TaptoZoom”,但正如我所说,我们需要将手势识别器连接到滚动视图。

          - (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
              // double tap zooms in
              [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleSingleTap:) object:nil];
              float newScale = [imageScrollView zoomScale] * 1.5;
              // Note we need to get location of the tap in the imageView coords, not the imageScrollView
              CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:imageView]];
              [imageScrollView zoomToRect:zoomRect animated:YES];
          }
          

          【讨论】:

          • 感谢@Tom,将位置转换为图像视图有效!
          • 这很棒。为我工作。
          【解决方案6】:

          在我的情况下是:

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

          【讨论】:

            【解决方案7】:

            我注意到,如果图像以小于 1 的 zoomScale 开始,则您使用的苹果无法正确缩放,因为 zoomRect 原点不正确。我对其进行了编辑以使其正常工作。代码如下:

            - (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {
            
            CGRect zoomRect;
            
            // the zoom rect is in the content view's coordinates. 
            //    At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
            //    As the zoom scale decreases, so more content is visible, the size of the rect grows.
            zoomRect.size.height = [self frame].size.height / scale;
            zoomRect.size.width  = [self frame].size.width / scale;
            
            
            // choose an origin so as to get the right center.
            zoomRect.origin.x = (center.x * (2 - self.minimumZoomScale) - (zoomRect.size.width  / 2.0));
            zoomRect.origin.y = (center.y * (2 - self.minimumZoomScale) - (zoomRect.size.height / 2.0));
            
            return zoomRect;
            }
            

            关键是这部分将中心值乘以(2 - self.minimumZoomScale)。 希望这会有所帮助。

            【讨论】:

            • 迟到的评论,但我无法抗拒;如果这有效:这纯粹是运气。乘以一个中心的坐标没有任何意义。如果您需要对中心执行翻译,则改为添加一个值。但最有可能的是,中心是不正确的,因为它是根据错误的坐标系参考计算的(例如,从错误的视图)
            【解决方案8】:

            我有同样的行为,这很令人沮丧...馈送到 UIScrollView 的矩形是完美的.. 但是我的观点,无论我做什么涉及以编程方式更改 zoomScale 总是缩放和缩放以协调0,0,无论如何。

            我试过只改变zoomScale,我试过zoomToRect,我都试过了,我在代码中触摸zoomScale的每一分钟,它都会去坐标0,0。

            我还必须在缩放操作后将 setContentSize 添加到滚动视图中调整大小的图像,否则我无法在缩放或捏合后滚动。

            这是 3.1.3 中的错误还是什么?

            【讨论】:

              【解决方案9】:

              我也有类似的情况,这是因为我没有通过将 center.x 和 center.y 值除以比例来调整它们(使用 center.x/scale 和 center.y/scale)。也许我没有正确阅读您的代码。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-08-22
                • 2015-01-12
                • 2015-11-06
                • 1970-01-01
                • 1970-01-01
                • 2012-07-20
                • 1970-01-01
                相关资源
                最近更新 更多