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

时间:2014-05-28 00:09:37

标签: ios objective-c uiscrollview

任何人都能准确描述-[UIScrollView zoomToRect:animated:]的行为吗?这种方法似乎确实做了一些复杂的事情,但Apple的文档记录很少。

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

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

Screen Recording

以下是我的示例项目中的代码:

@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仅仅是为了显示小于其自身大小的内容。我的用例是我的内容视图比滚动视图宽,但高度较短,我需要能够以编程方式滚动到此内容视图的右端或左端。

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

如果有人想知道,这就是我在这种情况下可以做的事情。我将看看它是否适用于滚动视图子类的单元测试我在我的现实生活项目中实现。但是,这并没有回答原来的问题"任何人都可以准确地描述-[UIScrollView zoomToRect:animated:]的行为?"所以我仍然希望得到更多答案。

嗯,这里(我讨厌像这样的hackery):

@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属性,在调用YES之前将其设置为-zoomToRect:animated:,如果NOanimated,则将其设置回NO。否则,我会在NO期间将属性设置为-scrollViewDidEndScrollingAnimation:(如果-zoomToRect:animated:没有导致任何规模变化,则调用此属性)和-scrollViewDidEndZooming:withView:atScale:(如果-zoomToRect:animated:则调用确实导致了规模的变化)。这是一个hacky解决方案,我担心它可能会破坏未来的iOS版本,但至少我已经完全支持单元测试:)