切换方向时如何正确定位UIScrollView的图像?

时间:2014-03-22 19:42:54

标签: ios objective-c cocoa-touch uiscrollview uiimageview

我很难弄清楚如何最好地重新定位我的UIScrollView图像视图(我现在有一个图库类型的应用程序,类似于Photos.app,特别是当您查看单个图像时,方向从纵向切换到横向,反之亦然。

我知道我最好的办法是操纵contentOffset属性,但我不确定它应该改成什么。

我玩过很多次,似乎无论出于什么原因,128的效果都很好。在我的视图控制器的viewWillLayoutSubviews方法中,我有:

    if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
        CGPoint newContentOffset = self.scrollView.contentOffset;

        if (newContentOffset.x >= 128) {
            newContentOffset.x -= 128.0;
        }
        else {
            newContentOffset.x = 0.0;
        }

        newContentOffset.y += 128.0;

        self.scrollView.contentOffset = newContentOffset;
    }
    else {
        CGPoint newContentOffset = self.scrollView.contentOffset;

        if (newContentOffset.y >= 128) {
            newContentOffset.y -= 128.0;
        }
        else {
            newContentOffset.y = 0.0;
        }

        newContentOffset.x += 128.0;

        self.scrollView.contentOffset = newContentOffset;
    }

它非常好用 。我讨厌它如何使用一个神奇的数字,我不知道它会来自何处。

此外,每当我缩放图像时,我都将其设置为居中(就像Photos.app一样):

- (void)centerScrollViewContent {
    // Keep image view centered as user zooms
    CGRect newImageViewFrame = self.imageView.frame;

    // Center horizontally
    if (newImageViewFrame.size.width < CGRectGetWidth(self.scrollView.bounds)) {
        newImageViewFrame.origin.x = (CGRectGetWidth(self.scrollView.bounds) - CGRectGetWidth(self.imageView.frame)) / 2;
    }
    else {
        newImageViewFrame.origin.x = 0;
    }

    // Center vertically
    if (newImageViewFrame.size.height < CGRectGetHeight(self.scrollView.bounds)) {
        newImageViewFrame.origin.y = (CGRectGetHeight(self.scrollView.bounds) - CGRectGetHeight(self.imageView.frame)) / 2;
    }
    else {
        newImageViewFrame.origin.y = 0;
    }

    self.imageView.frame = newImageViewFrame;
}

因此我需要它以使其正确定位,以便在重新定位时不会在图像周围显示黑色边框。 (这是第一个代码块中的检查所用的内容。)

基本上,我很好奇如何实现像Photos.app这样的功能,其中旋转滚动视图智能地重新定位内容,以便旋转前可见内容的中间是相同的后旋转,所以它感觉很连续。

1 个答案:

答案 0 :(得分:7)

每当scrollView在其UIScrollView值更改后布置其子视图时,您应该更改contentOffset的{​​{1}}属性。然后,当界面方向发生变化时,bounds的{​​{1}}会相应更改UIScrollView

为了使事情“正确”,您应该将bounds子类化并在那里进行所有调整。这也可以让您轻松重复使用“特殊”scrollView。

contentOffset计算函数应放在UIScrollView的{​​{1}}方法中。问题是这个方法不仅在contentOffset值被更改时调用,而且在srollView被缩放或滚动时调用。因此,如果由于方向更改导致UIScrollView发生更改,或者由于平移或捏合手势而导致调用layoutSubviews方法,则应跟踪bounds值。

因此bounds子类的第一部分应如下所示:

layoutSubviews

此处,每次bounds平移,缩放或更改UIScrollView时,都会调用- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Set the prevBoundsSize to the initial bounds, so the first time // layoutSubviews is called we won't do any contentOffset adjustments self.prevBoundsSize = self.bounds.size; } return self; } - (void)layoutSubviews { [super layoutSubviews]; if (!CGSizeEqualToSize(self.prevBoundsSize, self.bounds.size)) { [self _adjustContentOffset]; self.prevBoundsSize = self.bounds.size; } [self _centerScrollViewContent]; } 方法。 layoutSubviews方法负责在缩放视图的大小小于scrollView边界的大小时使缩放视图居中。并且,每次用户平移或缩放scrollView或旋转设备时都会调用它。它的实现与您在问题中提供的实现非常相似。不同之处在于此方法是在UIScrollView类的上下文中编写的,因此不使用bounds属性来引用缩放视图,这可能在_centerScrollViewContent类的上下文中不可用,使用UIScrollView委托方法。

self.imageView

但更重要的是UIScrollView方法。此方法负责调整viewForZoomingInScrollView:。这样,当- (void)_centerScrollViewContent { if ([self.delegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) { UIView *zoomView = [self.delegate viewForZoomingInScrollView:self]; CGRect frame = zoomView.frame; if (self.contentSize.width < self.bounds.size.width) { frame.origin.x = roundf((self.bounds.size.width - self.contentSize.width) / 2); } else { frame.origin.x = 0; } if (self.contentSize.height < self.bounds.size.height) { frame.origin.y = roundf((self.bounds.size.height - self.contentSize.height) / 2); } else { frame.origin.y = 0; } zoomView.frame = frame; } } 的{​​{1}}值更改时,更改前的中心点将保持在中心位置。并且由于条件语句,只有在_adjustContentOffset的{​​{1}}被更改时才会调用它(例如:方向更改)。

contentOffset

加成

我创建了一个有效的UIScrollView课程(此处为link to GitHub),以实现上述行为和其他奖励:

  • 您可以注意到在照片应用中,缩放照片,然后将其滚动到其中一个边界,然后旋转设备并不会将中心点保持在原位。相反,它将scrollView粘贴到该边界。如果您滚动到其中一个角然后旋转,则scrollView也会粘在该角落上。
  • 除了调整bounds之外,您可能还会发现还要调整scrollView的UIScrollView。例如,假设您正在以纵向模式查看照片,该照片已缩放以适合屏幕尺寸。然后,当您将设备旋转到横向模式时,您可能希望升级照片以利用可用空间。