【问题标题】:Autolayout is changing UIScrollView's contentOffset on rotation自动布局正在改变 UIScrollView 的 contentOffset 旋转
【发布时间】:2015-08-05 23:31:43
【问题描述】:

为了试验自动布局和 uiscrollview,我一直在使用 this example

我已经编辑为在滚动视图中包含 2 个视图,我已经设置了自动布局约束以将视图水平相邻放置,并且它们的大小设置为填充滚动视图框架。

UIView *beeView = [[[NSBundle mainBundle] loadNibNamed:@"BeeView" owner:nil options:nil] firstObject];
beeView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:beeView];
UIView *beeView2 = [[[NSBundle mainBundle] loadNibNamed:@"BeeView" owner:nil options:nil] firstObject];
beeView2.backgroundColor= [UIColor orangeColor];
beeView2.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:beeView2];

NSDictionary *views = @{@"beeView":beeView,@"beeView2":beeView2, @"scrollView":self.scrollView};
NSDictionary *metrics = @{@"height" : @200};
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[beeView(==scrollView)][beeView2(==beeView)]|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:metrics views:views]];
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[beeView(==scrollView)]|" options:kNilOptions metrics:metrics views:views]];

这很好地产生了我的意图。

但是,如果滚动视图的contentOffset 不为零并且设备从纵向旋转到横向,则滚动视图的内容偏移量会自动设置为32px。 (见截图)

我尝试保存 contentOffset 并在调用 scrollViewDidEndDecelerating: 时将其设置为这个保存的值,这可以工作,但很难看,因为滚动视图滚动到 32px 偏移量,然后返回到我想要的位置。

如何控制滚动视图的contentOffset?自动布局约束是否错误?在调整视图大小时,我是否可以添加额外的约束来控制contentOffset

【问题讨论】:

  • 尝试将H:|[beeView(==scrollView)][beeView2(==beeView)]|更改为H:|-[beeView(==scrollView)]-[beeView2(==beeView)]-|

标签: ios objective-c uiscrollview autolayout


【解决方案1】:

32px 是从哪里来的?和你的左右scrollView margin有关吗?

每次更改页面时它都会保留错误的偏移量吗?如果是这种情况,您应该查看您的 scrollView 的 contentInsets 值。

否则,我通过分页管理滚动视图的旋转是观察滚动视图的 contentSize:

首先,当你加载视图时,添加观察者:

[self.scrollView addObserver:self forKeyPath:NSStringFromSelector(@selector(contentSize)) options:0 context:nil];

然后,当 contentSize 值发生变化时,调整 contentOffset:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    if (object == self.scrollView && [keyPath isEqualToString:NSStringFromSelector(@selector(contentSize))]) {

        //Note that you should track your page index
        self.scrollView.contentOffset = CGPointMake(self.pageIndex * self.scrollView.bounds.size.width, self.scrollView.contentOffset.y);

    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

最后,卸载scrollView时移除观察者:

[self.scrollView removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentSize)) context:nil];

【讨论】:

  • 32px 只是我测量的,一定是随机故障,但是 addObserve 方法工作得很好,谢谢!
  • 这是个好建议;但是,请注意 UIKit 不保证支持 KVO。因此,虽然这种方法现在可能有效,但它可能会在未来的 iOS 更新中中断。另一种方法是继承UIScrollView 并覆盖setContentSize:。请参阅下面的答案以获取示例。
【解决方案2】:

在参考了之前的几篇帖子后:one & two。您似乎可以按照以下步骤之一找到您的解决方案:

  1. 以编程方式:如果您的 UIScrollViews 的父 VC 不直接位于 Nav Stack -

~编辑~

    // Without a Navigation Controller

    self.automaticallyAdjustsScrollViewInsets = NO;

    // With a Navigation Controller

    self.parentViewController.automaticallyAdjustsScrollViewInsets = NO;
    self.automaticallyAdjustsScrollViewInsets = NO;
  1. 界面生成器:属性检查器 -> 取消选中布局属性中的调整滚动视图插图

    李>
  2. 如果 仍然不成功:在呈现的 View Controller 的 ViewWillLayoutSubviews 方法中尝试设置以下每个 UIScrollView 属性:

    self.scrollView.contentOffset = CGPointZero;
    self.scrollView.contentInset = UIEdgeInsetsZero;
    

我猜选项 1 和 2 的组合会起作用,具体取决于导航堆栈的结构。

【讨论】:

  • 谢谢,但我没有使用任何类型的导航控制器,因此不会干扰它,我认为这是一些奇怪的自动布局故障。将 contentOffset 设置为零并不是特别有用,因为它只会将滚动视图设置回开头。
  • @DotSlashSlash 我很高兴您能够通过我们的答案之一解决您的问题。我很确定,既然您已经解释过您没有使用导航控制器,那么您是否在 VC 中使用 self.automaticallyAdjustsScrollViewInsets = NO; 也可以解决问题。
【解决方案3】:

对于 iOS 11.0 及更高版本,以下方法可以解决我的问题:

if (@available(iOS 11.0, *))
{
    self.myScrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

【讨论】:

  • 谢谢。这解决了我的滚动视图在滚动时或手动设置 contentoffset 后有额外的间距?
【解决方案4】:

我知道这是一个老问题,但如果它对任何人都有用 - 我创建了一个名为 LMPageViewUIScrollView 的子类,它自动应用必要的布局约束并调整旋转时的内容偏移量。该课程可作为 GitHub 上的 MarkupKit 项目的一部分获得。示例用法(Swift):

// Add 3 page views
pageView.addPage(view1)
pageView.addPage(view2)
pageView.addPage(view3)

// Show the 3rd page
pageView.currentPage = 2

可以在此处找到使用标记初始化页面视图的另一个示例:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 1970-01-01
    • 2011-09-25
    • 1970-01-01
    相关资源
    最近更新 更多