当图像放大太大时,UIPinchGestureRecognizer 表现得很有趣

Posted

技术标签:

【中文标题】当图像放大太大时,UIPinchGestureRecognizer 表现得很有趣【英文标题】:UIPinchGestureRecognizer acting funny when Image gets enlarged too big 【发布时间】:2011-11-02 11:35:43 【问题描述】:

我有一个简单的应用程序,我在其中将 UIPinchGestureRecognizer 和 UIPanGestureRecognizer 附加到 imageView,以便可以拖动和缩放它。我已经做到了,因此可以将 imageView 部分移出屏幕并从显示屏上最小化,但是图像的一小部分 75 像素仍保留在显示屏上,因此可以将图像拖回其上。因此,例如,如果我尝试将 imageView 从显示屏的右侧拖出,它将在剩余 75 个像素的 imageView 时停止,只留下足够的空间让我将其拖回。与缩放相同的概念,我创建的边界框架防止 imageView 被最小化显示。

无论如何,我的 UIPinchGestureRecognizer 委托方法中的边界代码存在这个问题。我做边界的方式是创建一个框架,它是 imageViews 超级视图的副本——除了它在每侧和顶部和底部被推入 75 像素。我检查 imageView 是否与此框架不相交,然后我知道它已到达右/左或上/下的边界之一。它在大多数情况下都有效,但是当我将图像放大到非常大(通常超过 1000 x 1000)时,边界不起作用 - 如果我执行超快速最小化比例,则 imageView 会被完全推离屏幕所以我不能把它拖回来。

我只是想知道为什么会这样。它与图像尺寸太大有关吗?还是我的代码有缺陷? (我在下面列出)。如果有人可以提供帮助将不胜感激。

- (void)scale:(UIPinchGestureRecognizer *)sender 

    if([sender state] == UIGestureRecognizerStateBegan) 
    
        lastScale = [sender scale];
    

    if ([sender state] == UIGestureRecognizerStateBegan || 
        [sender state] == UIGestureRecognizerStateChanged) 
    
        CGFloat currentScale = [[[sender view].layer valueForKeyPath:@"transform.scale"] floatValue];
        CGFloat newScale = 1 -  (lastScale - [sender scale]);// * (CropThePhotoViewControllerPinchSpeed);    
        newScale = MAX(newScale, CropThePhotoViewControllerMinScale / currentScale);

        CGFloat scaledWidth = newScale * sender.view.frame.size.width;
        CGFloat scaledHeight = newScale * sender.view.frame.size.height;

        CGRect translatedRect = CGRectMake(sender.view.frame.origin.x, sender.view.frame.origin.y, scaledWidth, scaledHeight);
        CGRect boundaryRect = CGRectMake(sender.view.superview.frame.origin.x + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.origin.y + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.size.width - (CropThePhotoViewControllerBoundaryBuffer * 2), sender.view.superview.frame.size.height - (CropThePhotoViewControllerBoundaryBuffer * 2));

        if (!(!CGRectIntersectsRect(boundaryRect,translatedRect) && newScale < 1))
        
            CGAffineTransform transform = CGAffineTransformScale([[sender view] transform], newScale, newScale);
            [[sender view] setTransform: transform];
            lastScale = [sender scale];;
        
     

【问题讨论】:

【参考方案1】:

我注意到我必须检查缩放的 NaN(不是数字)结果,然后分别处理它们。使用 isnan() 进行检查。

【讨论】:

感谢您的回复。我尝试寻找任何 NaN,但没有出现。我的问题出在其他地方,我在回答中写到了。【参考方案2】:

我发现出了什么问题。对于这行代码,我错误地设置了 x 和 y 值:

CGRect translatedRect = CGRectMake(sender.view.frame.origin.x, sender.view.frame.origin.y, scaledWidth, scaledHeight);

应该是:

CGRect translatedRect = CGRectMake(sender.view.frame.origin.x + (((sender.view.frame.size.width - scaledWidth) / 2)), sender.view.frame.origin.y + (((sender.view.frame.size.height - scaledHeight) / 2)), scaledWidth, scaledHeight);

我没有考虑到缩小图像视图时原点会移动的事实。

我做了这个改变,实际上更新了要改进的方法。现在,如果用户尝试最小化超出边界,而不是不执行缩放,而是将 imageView 向右移动到边界。这更顺畅,最终更好。测试后运行良好,但如果有人发现任何错误,请告诉我:

- (void)scale:(UIPinchGestureRecognizer *)sender 

    if([sender state] == UIGestureRecognizerStateBegan) 
    
        previousScale = [sender scale];
    


    if ([sender state] == UIGestureRecognizerStateBegan || 
        [sender state] == UIGestureRecognizerStateChanged) 
    
        CGFloat nextScale = 1 -  (previousScale - [sender scale]);// * (CropThePhotoViewControllerPinchSpeed); 

        nextScale = MAX(nextScale, CropThePhotoViewControllerMinScale / [[[sender view].layer valueForKeyPath:@"transform.scale"] floatValue]);

        CGFloat scaledWidth = nextScale * sender.view.frame.size.width;
        CGFloat scaledHeight = nextScale * sender.view.frame.size.height;
        CGFloat currentScale = [sender scale];

        CGRect translatedRect = CGRectMake(sender.view.frame.origin.x + (((sender.view.frame.size.width - scaledWidth) / 2)), sender.view.frame.origin.y + (((sender.view.frame.size.height - scaledHeight) / 2)), scaledWidth, scaledHeight);
        CGRect boundaryRect = CGRectMake(sender.view.superview.frame.origin.x + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.origin.y + CropThePhotoViewControllerBoundaryBuffer, sender.view.superview.frame.size.width - (CropThePhotoViewControllerBoundaryBuffer * 2), sender.view.superview.frame.size.height - (CropThePhotoViewControllerBoundaryBuffer * 2));

        if ((!CGRectIntersectsRect(boundaryRect,translatedRect)) && (nextScale < 1))        
        
            CGFloat leftScaledEdge, rightScaledEdge, topScaledEdge, bottomScaledEdge;
            CGFloat leftBoundary, rightBoundary, topBoundary, bottomBoundary;
            CGFloat nextXScale, nextYScale;

            nextXScale = CGFLOAT_MIN;
            nextYScale = CGFLOAT_MIN;

            rightScaledEdge = translatedRect.origin.x + translatedRect.size.width;
            leftScaledEdge = translatedRect.origin.x;
            bottomScaledEdge = translatedRect.origin.y + translatedRect.size.height;
            topScaledEdge = translatedRect.origin.y;

            leftBoundary = boundaryRect.origin.x;
            rightBoundary = boundaryRect.origin.x + boundaryRect.size.width; 
            topBoundary = boundaryRect.origin.y;
            bottomBoundary = boundaryRect.origin.y + boundaryRect.size.height;  

            if (rightScaledEdge < leftBoundary || leftScaledEdge > rightBoundary)
            
                if (rightScaledEdge < leftBoundary)
                
                    CGFloat adjustedWidth = sender.view.frame.size.width - fabsf((leftBoundary - (sender.view.frame.origin.x + sender.view.frame.size.width)));
                    nextXScale = (nextScale * (adjustedWidth)) / scaledWidth;
                
                else
                
                    CGFloat adjustedWidth = sender.view.frame.size.width - fabsf((rightBoundary - sender.view.frame.origin.x));
                    nextXScale = (nextScale * (adjustedWidth)) / scaledWidth;
                
            

            if (bottomScaledEdge < topBoundary || topScaledEdge > bottomBoundary)
            
                if (bottomScaledEdge < topBoundary)
                
                    CGFloat adjustedHeight = sender.view.frame.size.height - fabsf((topBoundary - (sender.view.frame.origin.y + sender.view.frame.size.height)));
                    nextYScale = (nextScale * (adjustedHeight)) / scaledHeight;
                
                else
                
                    CGFloat adjustedHeight = sender.view.frame.size.height - fabsf((bottomBoundary - sender.view.frame.origin.y));
                    nextYScale = (nextScale * (adjustedHeight)) / scaledHeight;

                
            

            if (nextXScale >= nextYScale)
            
                nextScale = nextXScale;
            
            else 
            
                nextScale = nextYScale;
            

            currentScale = nextScale - 1 + previousScale;
        

        CGAffineTransform transform = CGAffineTransformScale([[sender view] transform], nextScale, nextScale);
        [[sender view] setTransform: transform];
        previousScale = currentScale;
     

【讨论】:

以上是关于当图像放大太大时,UIPinchGestureRecognizer 表现得很有趣的主要内容,如果未能解决你的问题,请参考以下文章

wpf:当文本对于 1 行来说太大时,使文本块高度扩大

当整个文件太大时如何在python中使用mmap

当vector的大小太大时,如何解决C++中内存不足的问题?

RPC:当数组太大时,xdr_bytes“无法编码参数”

当 flex 项目变得太大时,iPad Safari 会忽略边距

PFFile 太大时应用程序崩溃