自动布局正在改变 UIScrollView 的 contentOffset 旋转
Posted
技术标签:
【中文标题】自动布局正在改变 UIScrollView 的 contentOffset 旋转【英文标题】:Autolayout is changing UIScrollView's contentOffset on rotation 【发布时间】: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)]-|
【参考方案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。您似乎可以按照以下步骤之一找到您的解决方案:
-
以编程方式:如果您的 UIScrollViews 的父 VC 不直接位于 Nav Stack -
~编辑~
// Without a Navigation Controller
self.automaticallyAdjustsScrollViewInsets = NO;
// With a Navigation Controller
self.parentViewController.automaticallyAdjustsScrollViewInsets = NO;
self.automaticallyAdjustsScrollViewInsets = NO;
界面生成器:属性检查器 -> 取消选中布局属性中的调整滚动视图插图。
李>如果 仍然不成功:在呈现的 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】:我知道这是一个老问题,但如果它对任何人都有用 - 我创建了一个名为 LMPageView
的 UIScrollView
的子类,它自动应用必要的布局约束并调整旋转时的内容偏移量。该课程可作为 GitHub 上的 MarkupKit 项目的一部分获得。示例用法(Swift):
// Add 3 page views
pageView.addPage(view1)
pageView.addPage(view2)
pageView.addPage(view3)
// Show the 3rd page
pageView.currentPage = 2
可以在此处找到使用标记初始化页面视图的另一个示例:
PageViewController.swift PageViewController.xml【讨论】:
以上是关于自动布局正在改变 UIScrollView 的 contentOffset 旋转的主要内容,如果未能解决你的问题,请参考以下文章