iPhone/iPad上旋转时禁用UIScrollView滚动

21

我正在使用UIScrollView,并在里面添加一张图像,每页一页。我在旋转iPhone时遇到了问题。

当我旋转iPhone时,scrollViewDidScroll(滚动视图代理方法)会被调用。因此,我的分页出现问题,页码会改变。

解决方案是什么?


你遇到了同样的问题吗?你解决了这个问题吗? - negersiu
1
@Maciulis,当时我具体做了什么我已经不记得了...但我检查了代码,并没有使用scrollViewDidScroll方法,而是使用了scrollViewDidEndDecelerating方法,并使用了一个全局变量来存储当前页面数。希望这能帮到你,或者请告诉我你需要什么信息。 - Amit Battan
6个回答

25

Raphaël的回答是问题的一个很好的描述,并提供了一个巧妙的解决方法。我遇到了完全相同的问题,最终使用了一个scrollingLocked标志,我在旋转开始前将其设置为YES(锁定),在旋转结束时设置为NO(解锁)。这样做可能比临时更改contentSize略微不太hacky。

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
                                duration:(NSTimeInterval)duration
{
    self.photoViewer.scrollingLocked = YES;
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromOrientation
{
    self.photoViewer.scrollingLocked = NO;
}

- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
    if (self.scrollingLocked)
    {
        return;
    }
    /* do normal scrollViewDidScroll: stuff */
}

照片查看器是哪个组件?因为它既不是滚动条,也不是视图。 - user529543
3
@matheszabi正在使用一个BOOL实例变量进行跟踪。或者,您可以直接使用UIScrollView的内置属性scrollEnabled。顺便说一下,在最后一张图片时,这仍然会触发scrollViewDidScroll,原因不明。 - Steven
iOS 8有类似的解决方案吗? - vivek241
@Steven 我最初赞了你的评论,但最终它对我没有起作用,因为无论如何,在之后 contentOffset 都已经改变了,就像你已经注意到的那样... - anneblue

14

我发现了一个奇怪的未记录行为,当旋转分页UIScrollView时。

当滚动视图位于最后一页并且用户更改方向时,操作系统会将UIScrollView滚动回几个像素以弥补高度和宽度之间的差异。

基本上,对于任何页面,我都收到以下调用。

willRotateToInterfaceOrientation:duration
willAnimateRotationToInterfaceOrientation:duration:
didRotateFromInterfaceOrientation:

最后一页的情况:

willRotateToInterfaceOrientation:duration
scrollViewDidScroll:
willAnimateRotationToInterfaceOrientation:duration:
didRotateFromInterfaceOrientation:

这也搞糊涂了我的页面。问题在于,在 willRotate 中,边界尚未被操作系统更新,在 willAnimate 中,您已经拥有了新的边界并且可以计算新的大小,但为时已晚...

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    CGSize tempSize = [self.pagingScrollView contentSize];
    NSUInteger padding = abs(pagingScrollView.frame.size.width - pagingScrollView.frame.size.height);
    tempSize.width += padding;
    [self.pagingScrollView setContentSize:tempSize];
    [...]
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration{
    CGSize newSize = ... // Compute new content size based on new orientation
    [self.pagingScrollView setContentSize:newSize];
}

这只是一种解决方法,但我在这个问题上花费了无数小时,并找不到一个优雅的解决方案。


1
您可以尝试使用Swift中的以下方法:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: { _ in
      // Execute before rotation
    }) { _ in
      //Execute after rotation
    }
}

1

Swift 4解决方案:

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        lui.l("apply previousTraitCollection: \(previousTraitCollection)")
        canScroll = true
    }


0
我的任务是实现横向滚动。设计是为竖屏而做的。我想到了一个办法,即在组件中添加ScrollView,或在Interface Builder中使用"嵌入ScrollView"选项。我原本以为这样可行,但事实并非如此。我正在使用Xcode 4.4、iOS 5.1(办公项目需要支持4.2),但问题仍然存在。
在Stack Overflow的问题iPhone SDK: UIScrollView does not scroll中有一行解决了问题。
另一个尝试是在Stack Overflow的问题iOS - UIScrollView is not working (it doesn't scroll at all - the image stays fixed)中,结合其他方法对我有所帮助,因此我编写了横屏滚动代码。
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromOrientation
{ 
    if( UIInterfaceOrientationIsPortrait( [[UIApplication sharedApplication] statusBarOrientation] ) ){
        scrollView.contentSize = portaitScrollSize;
    }
    else{//statusbar is Landscape
        scrollView.contentSize = landscapeScrollSize;
    }    
}

scrollView绑定到Interface Builder中的iVar视图。portaitScrollSizelandscapeScrollSize是私有变量。它们被初始化并且不会改变。 在my.h文件中:

IBOutlet UIScrollView *scrollView;

在我的.m文件中:
CGSize portaitScrollSize, landscapeScrollSize;

...

portaitScrollSize = CGSizeMake(320,440);
landscapeScrollSize = CGSizeMake(480,480);

我希望这能帮助有需要的人为肖像设计添加旋转+滚动功能。

别忘了在顶部组件上允许肖像+横向:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return TRUE;
}

0
除了Raphaël Mor的回答之外,如果您从纵向切换到横向,则内容大小和页面结构将会破坏。因此,为了保持当前的页面结构,只需在宽度上添加额外的内容大小即可。
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
    [self.scrollView setContentSize:CGSizeMake(self.scrollView.contentSize.width + 400, self.scrollView.contentSize.height)];
}

在屏幕方向改变后,请确保重新设置内容大小和偏移量:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self.scrollView setContentSize:CGSizeMake(self.scrollView.bounds.size.width *3, self.scrollView.bounds.size.height)];
    [self.scrollView setContentOffset:CGPointMake(self.scrollView.bounds.size.width * self.pageControl.currentPage, 0) animated:NO];

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接