【问题标题】:Redrawing UIScrollView contents after every zoom每次缩放后重绘 UIScrollView 内容
【发布时间】:2011-03-19 20:12:18
【问题描述】:

我在UIScrollView 中有一个UIView。每当UIScrollView 缩放发生变化时,我想以新的缩放级别重新绘制整个UIView

在 iOS UIScrollView 中调整 UIView 的大小以使其成为新大小,然后将转换设置回 Identity 来执行此操作,这样它就不会尝试进一步调整大小.但是,对于 iOS >= 3.2,更改身份也会更改 UIScrollView 的 zoomScale 属性。

结果是每当我缩放(比如 2 倍)时,我都会将嵌入的 UIView 调整为适当的大小,然后重新绘制它。但是现在(因为我将转换重置为 Identity),UIScrollView 再次认为它是 zoomScale 1,而不是 zoomScale 2。因此,如果我将 maxZoomScale 设置为 2,它仍会尝试进一步缩放,这是错误的。

我考虑过使用CATiledLayer,但我认为这对我来说还不够,因为我想在每次缩放后重新绘制,而不仅仅是像它试图做的那样在某些缩放阈值。

有谁知道如何在缩放时正确重绘UIView

【问题讨论】:

    标签: iphone uiscrollview ios


    【解决方案1】:

    汤姆,

    你的问题有点老了,但我想出了一个解决方案,所以我想我会提供一个答案,以防它对你或其他任何人有帮助。基本技巧是将滚动视图的zoomScale 重置为1,然后调整minimumZoomScalemaximumZoomScale,以便用户仍然可以按预期放大和缩小。

    在我的实现中,我对UIScrollView 进行了子类化并将其设置为自己的委托。在我的子类中,我实现了缩放所需的两个委托方法(如下所示)。 contentView 是我添加到我的UIScrollView 子类中的一个属性,以便为其提供实际显示内容的视图。

    所以,我的 init 方法看起来像这样(kMinimumZoomScalekMaximumZoomScale 在类的顶部是 #define):

    - (id)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
            self.autoresizesSubviews = YES;
            self.showsVerticalScrollIndicator = YES;
            self.showsHorizontalScrollIndicator = NO;
            self.bouncesZoom = YES;
            self.alwaysBounceVertical = YES;
            self.delegate = self;
    
            self.minimumZoomScale = kMinimumZoomScale;
            self.maximumZoomScale = kMaximumZoomScale;
        }
    
        return self;
    }
    

    然后我实现标准的UIScrollView 委托方法来进行缩放。我的ContentView 类有一个名为 zoomScale 的属性,它告诉它使用什么比例来显示其内容。它在其drawRect 方法中使用它来调整内容的大小。

    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)aScrollView {
        return contentView;
    }
    
    
    - (void)scrollViewDidEndZooming:(UIScrollView *)aScrollView withView:(UIView *)view atScale:(float)scale {
        CGFloat oldZoomScale = contentView.zoomScale;
        CGSize size = self.bounds.size;
    
        // Figure out where the scroll view was centered so that we can
        // fix up its offset after adjusting the scaling
        CGPoint contentCenter = self.contentOffset;
        contentCenter.x += size.width / (oldZoomScale * scale) / 2;
        contentCenter.y += size.height / (oldZoomScale * scale) / 2;
    
        CGFloat newZoomScale = scale * oldZoomScale;
        newZoomScale = MAX(newZoomScale, kMinimumZoomscale);
        newZoomScale = MIN(newZoomScale, kMaximumZoomscale);
    
        // Set the scroll view's zoom scale back to 1 and adjust its minimum and maximum
        // to allow the expected amount of zooming.
        self.zoomScale = 1.0;
        self.minimumZoomScale = kMinimumZoomScale / newZoomScale;
        self.maximumZoomScale = kMaximumZoomScale / newZoomScale;
    
        // Tell the contentView about its new scale. My contentView.zoomScale setter method
        // calls setNeedsDisplay, but you could also call it here
        contentView.zoomScale = newZoomScale;
    
        // My ContentView class overrides sizeThatFits to give its expected size with
        // zoomScale taken into account
        CGRect newContentSize = [contentView sizeThatFits];
    
        // update the content view's frame and the scroll view's contentSize with the new size
        contentView.frame = CGRectMake(0, 0, newContentSize.width, newContentSize.height);
        self.contentSize = newContentSize;
    
        // Figure out the new contentOffset so that the contentView doesn't appear to move
        CGPoint newContentOffset = CGPointMake(contentCenter.x - size.width / newZoomScale / 2,
                                               contentCenter.y - size.height / newZoomScale / 2);
        newContentOffset.x = MIN(newContentOffset.x, newContentSize.width - size.width);
        newContentOffset.x = MAX(0, newContentOffset.x);
        newContentOffset.y = MIN(newContentOffset.y, newContentSize.height - .size.height);
        newContentOffset.y = MAX(0, newContentOffset.y);
        [self setContentOffset:newContentOffset animated:NO];
    }
    

    【讨论】:

    • 非常感谢您的解决方案!这解决了my question。您能否在此处留下您的答案的链接,以便我给予您适当的答复?
    • 如果该方法用于缩放 CATiledLayer,则需要在调用 setNeedsDisplay 之前清除 tile-cache。清除 CATiledLayerCache 的解决方案可用here
    • 您能否解释一下 contentSize 的属性以及它是如何设置的以及它实际上是什么。谢谢
    【解决方案2】:

    就我而言,我有一个图像视图,并且在图像视图之上我还有几个其他图像视图。这是我想出的实现并且运行良好:

    - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(double)scale{
        NSLog(@"finished zooming");
    
        NSLog(@"position x :%f",pin1.frame.origin.x);
        NSLog(@"position y :%f",pin1.frame.origin.y);
    
    
        CGRect frame = pin1.frame;
        frame.origin.x = pin1.frame.origin.x * scale;
        frame.origin.y = pin1.frame.origin.y * scale;
        pin1.frame = frame;
    
        NSLog(@"position x new :%f",pin1.frame.origin.x);
        NSLog(@"position y new:%f",pin1.frame.origin.y);
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-15
      • 2011-12-20
      • 2019-07-14
      • 2011-04-26
      • 2010-10-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      相关资源
      最近更新 更多