自动布局 + UIScrollView 和单个子视图

Posted

技术标签:

【中文标题】自动布局 + UIScrollView 和单个子视图【英文标题】:Auto Layout + UIScrollView and single subview 【发布时间】:2015-03-14 02:54:40 【问题描述】:

只是在玩 Auto Layout 和 UIScrollView。我在这里想念什么?这会在屏幕底部显示一个蓝色滚动视图,但我看不到 contentView。视图调试器也无话可说。有任何想法吗?

//
//  ViewController.m
//  Fit
//
//  Created by Adam Dahan on 2015-03-13.
//  Copyright (c) 2015 Adam Dahan. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

    UIScrollView *scrollView;
    UIView *contentView;

@end

@implementation ViewController

- (void)viewDidLoad

    [super viewDidLoad];

    [self createViews];
    [self constrainScrollView];
    [self constrainContentView];


- (void)createViews

#pragma Initialize a scrollView
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.backgroundColor = [UIColor blueColor];
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    [self.view addSubview:scrollView];

#pragma Initialize a contentView for the scrollView
    contentView = [[UIView alloc] initWithFrame:CGRectZero];
    contentView.backgroundColor = [UIColor redColor];
    contentView.translatesAutoresizingMaskIntoConstraints = NO;
    [scrollView addSubview:contentView];


- (void)constrainScrollView


#pragma scrollView vertical constraints
    NSArray *cns = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[scrollView(40)]|"
                                                       options:0
                                                       metrics:nil
                                                                views:NSDictionaryOfVariableBindings(scrollView)];
    [self.view addConstraints:cns];

#pragma scrollView horizontal constraints
    cns = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                              options:0
                                              metrics:nil
                                                views:NSDictionaryOfVariableBindings(scrollView)];
    [self.view addConstraints:cns];


- (void)constrainContentView


#pragma contentView vertical constraints
    NSArray *cns = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|"
                                              options:0
                                              metrics:nil
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];

#pragma contentView horizontal constraints
    cns = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|"
                                              options:0
                                              metrics:nil
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];


@end

【问题讨论】:

我认为您需要设置内容大小:scrollView.contentSize = 。您通常在 scrollView 上使用约束,而不是在其内容视图上。您设置 scrollView 的内容大小,其余部分由它处理。 【参考方案1】:

使用自动布局时,ScrollView 会稍微复杂一些。框架是根据与其他视图的约束来定义的(因为您将是您在 constainScrollView 方法中添加的那些)。

contentSize 的定义取决于scrollView 内部视图的约束。对于您的情况, contentSize 是 (0,0) 因为内部视图没有宽度或高度约束。

我想你希望这个内部视图填充滚动视图。那么你的约束应该是这样的:

- (void)constrainContentView

    [self.view layoutIfNeeded]; // This causes the scrollview width and height to be calculated based on the constraints you sent in the previous method
    // You could check by adding a breakpoint here, if the scrollview has the frame you would expect

#pragma contentView vertical constraints
    NSArray *cns = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[contentView(height)]-|"
                                              options:0
                                              metrics:@"height":@(CGRectGetHeight(scrollView.frame))
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];

#pragma contentView horizontal constraints
    cns = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[contentView(width)]-|"
                                              options:0
                                              metrics:@"width":@(CGRectGetWidth(self.view.frame))
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];

您为widthheight 设置的实际值取决于您的需要。

重要的是scrollView 内的视图需要以这样的方式设置约束,以便可以毫无歧义地计算contentSize。这意味着如果视图没有固有大小(如 UIButtonUILabel),则需要显式添加宽度/高度约束。

由于明确设置了宽度和高度,在方向更改时,您需要更新约束,以便内部视图具有正确的尺寸。

希望这能解决您的问题。

【讨论】:

感谢您的回答 :) 我想我对 VFL 感到困惑,因为据我了解 H:|-[view]-| (pipe-view-pipe) 表示超级视图宽度。所以我会认为这会自然地扩大屏幕的整个宽度。 不客气 :) 是的,这就是scrollViews 的自动布局有点棘手的原因,因为它们在用于定义frame 的约束之间有所不同以及用于定义contentSize 的那些。人们不会期望它们是不同的。无论如何,很高兴你解决了你的问题【参考方案2】:

你真的应该看看Technical Note TN2154 UIScrollView And Autolayout。

你的方式让系统无法决定scrollView的contentSize。

主要思想是让scrollView无论你选择哪种方式都知道contentSize是什么。

【讨论】:

那为什么它需要 contentSize 才能工作? @arcognito 实际上,如果您使用带有 ScrollView 的自动布局,系统将为您计算 contentSize。所以它需要能够计算出正确尺寸的约束。

以上是关于自动布局 + UIScrollView 和单个子视图的主要内容,如果未能解决你的问题,请参考以下文章

ios: uiscrollview 和 uiview 自动布局

UIScrollView 和自动布局

自动布局和 UIScrollView

带有 UIScrollView 的纯自动布局

使用 UIScrollView 和自动布局的图像滑块

具有自动布局和设备旋转的 UIScrollView