40

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

一个UIViewController,一个孩子UIScrollView和一个UIImageView在这UIScrollView。我将 设置为UIImageView足以突破可见区域的高度(即高于1024pt),并将Bottom space to superviewmy 的约束设置UIImageView为固定的正值(20例如)。

项目布局

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

这个不好解释,我试着画一下: 上一段的视觉表示

如果您想测试/查看源代码(或情节提要,我没有编辑任何一行代码)。我在我的github上放了一个小demo:https ://github.com/guillaume-algis/iOSAutoLayoutScrollView

我确实阅读了iOS 6 更改日志和关于这个特定主题的解释,并认为这是第二个选项(纯自动布局)的正确实现,但在这种情况下,为什么UIScrollView行为如此不规律?我错过了什么吗?

编辑:这与#12580434 uiscrollview-autolayout-issue 完全相同。答案只是解决方法,因为有人找到了解决此问题的正确方法,还是这是 iOS 错误?

编辑 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;
}

这基本上将偏移量保存在 中viewWillAppear,将其重置为原点,然后恢复 中的值viewDidAppear。问题似乎发生在这两个调用之间,但我找不到它的起源。

4

7 回答 7

22

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

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

解决方案

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

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

和沃!有用!

于 2013-03-11T22:48:22.347 回答
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;
}
于 2013-08-21T19:24:27.620 回答
5

对我来说,我去了 IB,点击了包含滚动视图的视图控制器。然后我转到属性检查器 -> 视图控制器 -> 扩展边缘 -> 取消选中“顶部栏下方”和“底部栏下方”。

于 2014-12-05T20:27:19.170 回答
2

找到简单的解决方案,放

[self setAutomaticallyAdjustsScrollViewInsets:NO];

在您的 ViewControllers viewDidLoad 方法中

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

    [self setAutomaticallyAdjustsScrollViewInsets:NO];
}
于 2016-09-08T13:05:04.620 回答
0

我在 UIViewController 中使用 UIScrollView 时遇到了类似的问题,顶部的额外空间在 Storyboard 中不可见。我的解决方案是取消选中 ViewController 故事板属性上的“调整滚动视图插图”:请参阅运行时滚动视图中的答案额外空间(插图)

于 2014-10-25T23:05:40.897 回答
-2

添加一个全局属性 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];
}
于 2014-02-28T15:03:29.017 回答
-4

看起来问题已经解决dispatch_asyncviewWillAppear:

- (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;
    });
}
于 2013-08-27T20:43:21.280 回答