UIScrollView使用自动布局错误偏移

时间:2013-03-11 18:08:55

标签: ios uiscrollview autolayout

我有一个相当简单的视图配置:

UIViewController,此UIScrollView中有一个小孩UIImageView和一个UIScrollView。 我将UIImageView设置为足以突破可见区域的高度(即更高到1024pt),并将Bottom space to superview的{​​{1}}约束设置为固定的正值(例如UIImageView)。

project layout

整个设置按预期工作,图像在其父级中滚动得很好。 除非滚动视图(如果滚动到视图底部,效果更明显),然后消失,再次出现(您切换到另一个视图并返回)滚动值将恢复,但内容为滚动视图移动到其父视图的外部顶部。

这个解释起来并不简单,我会尝试绘制它: visual representation of previous paragraph

如果您想测试/查看源(或故事板,我没有编辑一行代码)。我在我的github上放了一个小小的演示:https://github.com/guillaume-algis/iOSAutoLayoutScrollView

我确实阅读了iOS 6 changelog以及关于这个特定主题的解释,并认为这是第二个选项(纯自动布局)的正确实现,但在这种情况下,为什么20表现得很好如此不规律?我错过了什么吗?

编辑:这与#12580434 uiscrollview-autolayout-issue完全相同。答案只是解决方法,因为任何人都找到了解决这个问题的正确方法,或者这是一个iOS错误吗?

编辑2 :我找到了另一种解决方法,它将滚动位置保持在用户离开的状态(这是对12580434已接受的答案的改进):

UIScrollView

这基本上保存了@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; } 中的偏移量,将其重置为原点,然后恢复viewWillAppear中的值。问题似乎发生在这两个调用之间,但我无法找到它的起源。

7 个答案:

答案 0 :(得分:22)

是的,UIScrollView在纯自动布局环境中发生了一些奇怪的事情。第二十次重新阅读iOS SDK 6.0 release notes我发现:

  

请注意,您可以通过在视图和滚动视图子树外部的视图之间创建约束(例如滚动视图的超级视图),使滚动视图的子视图显示为浮动(不滚动)其他滚动内容。

解决方案

将子视图连接到外部视图。换句话说,就是嵌入了scrollview的视图。

由于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)]];
}

和vau!它有效!

答案 1 :(得分:10)

编辑对我不起作用。但这有效:

-(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;
}

答案 2 :(得分:5)

对我来说,我去了IB点击了包含滚动视图的视图控制器。然后我去了属性检查员 - >视图控制器 - >延伸边缘 - >取消选中"在顶栏下#34;和"在底栏"。

答案 3 :(得分:2)

找到简单的解决方案,只需添加

[self setAutomaticallyAdjustsScrollViewInsets:NO];
ViewControllers中的

viewDidLoad方法

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    [self setAutomaticallyAdjustsScrollViewInsets:NO];
}

答案 4 :(得分:0)

我在UIViewController中使用UIScrollView时遇到了类似的问题,其中一个顶部额外空间在Storyboard中不可见。我的解决方案是取消选中ViewController故事板属性上的“调整滚动视图插图”:请参阅回答Extra Space (inset) in Scroll View at run time

答案 5 :(得分:-1)

添加全局属性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];
}

答案 6 :(得分:-4)

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;
    });
}