-[UIScrollView zoomToRect:animated:] contentSize < bounds.size 时的奇怪行为

Posted

技术标签:

【中文标题】-[UIScrollView zoomToRect:animated:] contentSize < bounds.size 时的奇怪行为【英文标题】:-[UIScrollView zoomToRect:animated:] weird behavior when contentSize < bounds.size 【发布时间】:2014-05-28 00:09:37 【问题描述】:

谁能准确描述-[UIScrollView zoomToRect:animated:] 的行为?这种方法看起来确实做了一些复杂的事情,但是苹果的文档非常少。

当内容大小小于滚动视图的宽度和/或高度时,我会遇到这种方法的不可预知的行为。在某些情况下,此方法会导致滚动视图在它应该为 0 时具有负的内容偏移量。传递稍微不同的 rects,它会将内容偏移量保留为 0,就像我预期的那样。

为了演示这种奇怪的行为,我设置了一个示例项目,其中包含一个 大小为 (200, 200) 的滚动视图,其中包含一个 大小为 (100, 100) 的内容视图。我希望 缩放到 rect ((0, 0), (200, 200)) 内容视图应该将内容留在左上角(即什么都不应该发生)。但是,它实际上会导致内容滚动到滚动视图边界的右下角(内容偏移量 (-100, -100))。为什么会这样?

这是我的示例项目中的代码:

@implementation RootViewController

- (void)loadView 
    self.view = [[UIView alloc] init];

    self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    self.scrollView.delegate = self;
    self.scrollView.backgroundColor = [UIColor whiteColor];
    self.scrollView.minimumZoomScale = .5;
    self.scrollView.maximumZoomScale = 4;

    self.contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    self.contentView.backgroundColor = [UIColor redColor];
    [self.contentView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap)]];

    [self.scrollView addSubview:self.contentView];
    self.scrollView.contentSize = self.contentView.frame.size;
    [self.view addSubview:self.scrollView];


- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView 
    return self.contentView;


- (void)handleTap 
    [self.scrollView zoomToRect:CGRectMake(0, 0, 200, 200) animated:YES]; // Try changing to 199, 199 to get completely different behavior


@end

感谢您的任何见解!现在我猜UIScrollView 的设计目的不是显示小于其自身大小的内容。我的用例是我可能有一个比滚动视图更宽但高度更短的内容视图,我需要能够以编程方式滚动到此内容视图的右端或左端。

【问题讨论】:

内容大小小于界限有什么意义?设置未使用的维度以匹配边界并继续前进。 哦,ios 会让你通过滚动到用户无法滚动到的地方来上吊。解决方案:不要那样做。 @jaggedcow 是的,我正在设置contentSize。即使在那种退化的情况下,我也希望将内容放在左上角。 对于您的用例,为什么要使用 zoomToRect: 而不是 scrollToRect: 或仅设置 contentOffset? 看看我的例子可能对你有帮助:github.com/mattneub/Programming-iOS-Book-Examples/tree/master/… 向你展示如何在保持可缩放视图居中的同时允许缩放。 【参考方案1】:

除非有人有更好的答案,否则我将得出结论,当结果 contentSize 在任一维度上小于 bounds 大小时,调用 -zoomToRect:animated: 会产生未定义的结果。换句话说,如果你想安全的话,内容应该比滚动视图大。

【讨论】:

【参考方案2】:

如果有人想知道,这就是我在这种情况下可能会做的事情。我将看看它是否与我在现实生活项目中实现的滚动视图子类的单元测试配合得很好。然而,这并没有回答“谁能准确描述-[UIScrollView zoomToRect:animated:] 的行为?”的原始问题。所以我仍然希望得到更多的答案。

好吧,就这样吧(我讨厌这样的骇客):

@implementation TBScrollView // Subclass of UIScrollView

- (void)setContentOffset:(CGPoint)contentOffset 
    contentOffset.x = MAX(contentOffset.x, 0);
    contentOffset.y = MAX(contentOffset.y, 0);
    [super setContentOffset:contentOffset];


- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated 
    contentOffset.x = MAX(contentOffset.x, 0);
    contentOffset.y = MAX(contentOffset.y, 0);
    [super setContentOffset:contentOffset animated:animated];


@end

编辑:不幸的是,这有一个不幸的副作用,即您不能再在左侧反弹滚动以获取更大的图像,而应该允许这样做(需要负内容偏移)。我将为我的用例寻找另一种解决方案。

编辑 2: 我通过仅在发生 -zoomToRect:animated: 动画时禁用负内容偏移来解决上述副作用。我声明了一个BOOL 属性,在调用-zoomToRect:animated: 之前将其设置为YES,然后如果animatedNO 则将其设置回NO。否则,我在-scrollViewDidEndScrollingAnimation:(如果-zoomToRect:animated: 没有导致比例发生任何变化时调用)和-scrollViewDidEndZooming:withView:atScale:(如果-zoomToRect:animated: 确实导致比例发生变化则调用)期间将属性设置为NO。这是一种 hacky 解决方案,我担心它可能会在未来的 iOS 版本中中断,但至少我的单元测试都支持它:)

【讨论】:

你不需要两个方法;第一个调用第二个。 从我的测试来看,第一个不会调用第二个 是的,你是对的,我把它倒过来了:第二个调用第一个。

以上是关于-[UIScrollView zoomToRect:animated:] contentSize < bounds.size 时的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法可以改变 UIScrollView 的 zoomToRect 的持续时间吗?

如果您的 UIScrollView 已经处于该缩放级别,则 zoomToRect 啥也不做

如果我在 UIScrollView 中有 UIViewController,如何以编程方式使 UIScrollview zoomToRect?

目标C中UIScrollView中的zoomToRect方法不起作用

导致 UIScrollView zoomToRect: 只显示一部分

-[UIScrollView zoomToRect:animated:] contentSize < bounds.size 时的奇怪行为