ios UIScrollView 错误的自动布局偏移
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15345522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIScrollView wrong offset with Auto Layout
提问by Guillaume Algis
I have a fairly simple view configuration:
我有一个相当简单的视图配置:
A UIViewController
, with a child UIScrollView
and a UIImageView
in this UIScrollView
.
I set the UIImageView
with a height sufficient to break out of the visible area (ie. higher to 1024pt
), and set the Bottom space to superview
constraint of my UIImageView
to a fixed positive value (20
for example).
一个UIViewController
,带着一个孩子UIScrollView
,一个UIImageView
在这UIScrollView
。我将 的UIImageView
高度设置为足以突破可见区域(即更高到1024pt
),并将Bottom space to superview
my的约束设置UIImageView
为固定的正值(20
例如)。
The whole setup works as expected, the image scrolls nicely in its parent. Except when the view is scrolled (the effect is more visible if you scrolled to the bottom of the view), then disappear, and appear again (you switched to another view and came back) the scrolling value is restored, but the content of the scroll view is moved to the outside top part of its parent view.
整个设置按预期工作,图像在其父级中很好地滚动。除了视图滚动时(滚动到视图底部效果更明显),然后消失,再次出现(您切换到另一个视图并返回)滚动值恢复,但滚动视图移动到其父视图的外部顶部。
This is not simple to explain, I'll try to draw it:
这个不好解释,我试着画一下:
If you want to test/view the source (or the storyboard, I did not edit a single line of code). I put a little demo on my github: https://github.com/guillaume-algis/iOSAutoLayoutScrollView
如果你想测试/查看源代码(或故事板,我没有编辑一行代码)。我在我的 github 上放了一个小演示:https: //github.com/guillaume-algis/iOSAutoLayoutScrollView
I did read the iOS 6 changelogand the explanation on this particular topic, and think this is the correct implementation of the second option (pure auto layout), but in this case why is the UIScrollView
behaving so erratically ? Am I missing something ?
我确实阅读了iOS 6 更新日志和关于这个特定主题的解释,并认为这是第二个选项(纯自动布局)的正确实现,但在这种情况下,为什么UIScrollView
行为如此不规律?我错过了什么吗?
EDIT: This is the exact same issue as #12580434 uiscrollview-autolayout-issue. The answers are just workarounds, as anyone found a proper way to fix this or is this a iOS bug ?
编辑:这与#12580434 uiscrollview-autolayout-issue 完全相同。答案只是解决方法,因为有人找到了解决此问题的正确方法还是这是 iOS 错误?
EDIT 2: I found another workaround, which keep the scroll position in the same state the user left it (this is an improvement over 12580434's accepted answer):
编辑 2:我找到了另一种解决方法,它将滚动位置保持在用户离开它的相同状态(这是对12580434接受的答案的改进):
@interface GAViewController ()
@property CGPoint tempContentOffset;
@end
@implementation GAViewController
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.tempContentOffset = self.mainScrollView.contentOffset;
self.scrollView.contentOffset = CGPointZero;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.scrollView.contentOffset = self.tempContentOffset;
}
This basically save the offset in viewWillAppear
, reset it to the origin, and then restore the value in viewDidAppear
. The problem seems to occur between these two calls, but I can't find its origin.
这基本上保存了 中的偏移量viewWillAppear
,将其重置为原点,然后恢复 中的值viewDidAppear
。问题似乎发生在这两个调用之间,但我找不到它的起源。
采纳答案by Mark Kryzhanouski
Yeah, something strange happened with UIScrollView in pure autolayout environment. Re-reading the iOS SDK 6.0 release notesfor the twentieth time I found that:
是的,在纯自动布局环境中 UIScrollView 发生了一些奇怪的事情。第二十次重读iOS SDK 6.0发行说明,我发现:
Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints between the view and a view outside the scroll view's subtree, such as the scroll view's superview.
请注意,您可以通过在视图和滚动视图子树外部的视图(例如滚动视图的超级视图)之间创建约束,使滚动视图的子视图看起来浮动(而不是滚动)在其他滚动内容上。
Solution
解决方案
Connect your subview to the outer view. In another words, to the view in which scrollview is embedded.
将您的子视图连接到外部视图。换句话说,嵌入滚动视图的视图。
As IB does not allow us set up constraints between the imageView and a view outside the scroll view's subtree, such as the scroll view's superview then I've done it in code.
由于 IB 不允许我们在 imageView 和滚动视图子树之外的视图之间设置约束,例如滚动视图的超级视图,所以我已经在代码中完成了。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view removeConstraints:[self.view constraints]];
[self.scrollView removeConstraints:[self.scrollView constraints]];
[self.imageView removeConstraints:[self.imageView constraints]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_imageView(700)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imageView(1500)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
}
And vau! It works!
还有沃!有用!
回答by Pion
The edit didn't work for me. But this worked:
编辑对我不起作用。但这有效:
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
self.tempContentOffset = self.scrollView.contentOffset;
self.scrollView.contentOffset = CGPointZero;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.scrollView.contentOffset = self.tempContentOffset;
}
回答by Andy
For me I went to the IB clicked my view controller that contains the scroll view. Then I went to Attribute Inspector -> View Controller -> Extend Edges -> Uncheck "Under Top Bars" and "Under Bottom Bars".
对我来说,我去 IB 单击了包含滚动视图的视图控制器。然后我转到属性检查器 -> 视图控制器 -> 扩展边缘 -> 取消选中“在顶部栏下”和“在底部栏下”。
回答by Purushottam Sain
Simple solution found, Just put
找到了简单的解决方案,只需放置
[self setAutomaticallyAdjustsScrollViewInsets:NO];
in your ViewControllers viewDidLoad method
在您的 ViewControllers viewDidLoad 方法中
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self setAutomaticallyAdjustsScrollViewInsets:NO];
}
回答by Maxime T
I had a similar problem using a UIScrollView in a UIViewController with a top extra space that was not visible in Storyboard. The solution for me was to uncheck the "Adjust Scroll View Insets" on the ViewController storyboard properties : see answer Extra Space (inset) in Scroll View at run time
我在 UIViewController 中使用 UIScrollView 时遇到了类似的问题,顶部额外空间在 Storyboard 中不可见。我的解决方案是取消选中 ViewController 故事板属性上的“调整滚动视图插入”:在运行时查看滚动视图中的额外空间(插入)
回答by Misha van Broekhoven
Add a global property contentOffset and save the current contentOffset in viewDidDisappear. Once you return the method viewDidLayoutSubviews will be called and you can set your original contentOffset.
添加全局属性 contentOffset 并将当前 contentOffset 保存在 viewDidDisappear 中。一旦您返回方法 viewDidLayoutSubviews 将被调用,您可以设置您的原始 contentOffset。
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self.scrollView setContentOffset:self.contentOffset animated:FALSE];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.contentOffset = self.scrollView.contentOffset;
[self.scrollView setContentOffset:CGPointMake(0, 0) animated:FALSE];
}
回答by chebur
Looks like the problem solved with the dispatch_async
during the viewWillAppear:
看起来问题解决dispatch_async
了viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CGPoint originalContentOffset = self.scrollView.contentOffset;
self.scrollView.contentOffset = CGPointZero;
dispatch_async(dispatch_get_main_queue(), ^{
self.scrollView.contentOffset = originalContentOffset;
});
}