具有自动布局约束的 UIScrollView:自动计算内容大小
UIScrollView with Auto Layout Constraints: Auto Content Size Calculation
我在使用自动布局约束的 UIScrollView 时遇到问题。我有以下视图层次结构,通过 IB 设置了约束:
- ScrollView (leading, trailing, bottom and top spaces to Superview)
-- ContainerView (leading, trailing, bottom and top spaces to ScrollView)
--- Button 1 (full width, **top space to ContainerView**)
--- Button 2 (full width, below Button 1)
--- Button n (full width, below Button n-1, **bottom space to ContainerView**)
我想要一个简单的滚动标签按钮列表。这是我的代码:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor redColor]];
[self.contentView setBackgroundColor:[UIColor yellowColor]];
UIView *lastView= self.contentView; // use for top constraint
NSInteger topBottomMargin= 10, leftRightMargin= 16;
for (int i=0; i<10; i++) {
UIButton *button= [UIButton buttonWithType:UIButtonTypeSystem];
button.translatesAutoresizingMaskIntoConstraints= NO;
[button setTitle:[NSString stringWithFormat:@"Button %d", i] forState:UIControlStateNormal];
[self.contentView addSubview:button];
// add constraints
// top
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:lastView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:button
attribute:NSLayoutAttributeTop
multiplier:1.0 constant:-topBottomMargin]];
// left
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:button
attribute:NSLayoutAttributeLeading
multiplier:1.0 constant:-leftRightMargin]];
// right
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:button
attribute:NSLayoutAttributeTrailing
multiplier:1.0 constant:leftRightMargin]];
lastView= button;
}
// bottom
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:lastView
attribute:NSLayoutAttributeBottom
multiplier:1.0 constant:topBottomMargin]];
}
contentView的高度好像是0!但是它的顶部和底部都有限制。应该是这样的:
但是我的代码是这样的。任何帮助都会很棒。
由于您在 contentView 上使用自动布局约束,它的高度(框架)在 viewDidLoad 方法中将为零。您应该将您的代码移动到 viewDidLayoutSubviews
方法中并尝试在那里添加您的按钮。
你应该在那里得到 contentView 的高度。如果可行,请告诉我。希望这有帮助。
参考这个问题:iOS AutoLayout - get frame size width
您可以向容器视图添加约束以将视图滚动为等高和等宽。此外,当您向按钮添加约束时,不要忘记向按钮添加底部约束,因为它将决定滚动视图的结束(内容大小)。
我不认为我们不能将自动布局直接添加到 ScrollView 内部的 ContainerView 中,并将 Intrinsic Size 作为默认值,因此我以编程方式将 ContainerView 添加为子视图:
- (void)viewDidLoad{
[super viewDidLoad];
self.contentView = [[UIView alloc] initWithFrame:CGRectZero];
[self.scrollView addSubview:self.contentView];
//Then add your button here as normal.
//...
}
Gurtej Singh 是对的,我们必须更新 viewDidLayoutSubviews 中的框架:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
//Don't for get to update your self.scrollView.contentSize if you want to able to scroll
//...
//Update your contentView frame based on scrollview frame and self.scrollView.contentSize.
self.contentView.frame = self.scrollView.bounds or ....;
}
我只是想帮忙,这可能不是一个好的解决方案,但它对我有用。
我找到了我一直在寻找的解决方案 here:
[super viewDidLoad];
UIScrollView* sv = [UIScrollView new];
sv.backgroundColor = [UIColor whiteColor];
sv.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:sv];
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[sv]|"
options:0 metrics:nil
views:@{@"sv":sv}]];
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[sv]|"
options:0 metrics:nil
views:@{@"sv":sv}]];
UILabel* previousLab = nil;
for (int i=0; i<30; i++) {
UILabel* lab = [UILabel new];
lab.translatesAutoresizingMaskIntoConstraints = NO;
lab.text = [NSString stringWithFormat:@"This is label %i", i+1];
[sv addSubview:lab];
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[lab]"
options:0 metrics:nil
views:@{@"lab":lab}]];
if (!previousLab) { // first one, pin to top
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[lab]"
options:0 metrics:nil
views:@{@"lab":lab}]];
} else { // all others, pin to previous
[sv addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[prev]-(10)-[lab]"
options:0 metrics:nil
views:@{@"lab":lab, @"prev":previousLab}]];
}
previousLab = lab;
}
// last one, pin to bottom and right, this dictates content size height
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[lab]-(10)-|"
options:0 metrics:nil
views:@{@"lab":previousLab}]];
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[lab]-(10)-|"
options:0 metrics:nil
views:@{@"lab":previousLab}]];
// look, Ma, no contentSize!
我在使用自动布局约束的 UIScrollView 时遇到问题。我有以下视图层次结构,通过 IB 设置了约束:
- ScrollView (leading, trailing, bottom and top spaces to Superview)
-- ContainerView (leading, trailing, bottom and top spaces to ScrollView)
--- Button 1 (full width, **top space to ContainerView**)
--- Button 2 (full width, below Button 1)
--- Button n (full width, below Button n-1, **bottom space to ContainerView**)
我想要一个简单的滚动标签按钮列表。这是我的代码:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor redColor]];
[self.contentView setBackgroundColor:[UIColor yellowColor]];
UIView *lastView= self.contentView; // use for top constraint
NSInteger topBottomMargin= 10, leftRightMargin= 16;
for (int i=0; i<10; i++) {
UIButton *button= [UIButton buttonWithType:UIButtonTypeSystem];
button.translatesAutoresizingMaskIntoConstraints= NO;
[button setTitle:[NSString stringWithFormat:@"Button %d", i] forState:UIControlStateNormal];
[self.contentView addSubview:button];
// add constraints
// top
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:lastView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:button
attribute:NSLayoutAttributeTop
multiplier:1.0 constant:-topBottomMargin]];
// left
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:button
attribute:NSLayoutAttributeLeading
multiplier:1.0 constant:-leftRightMargin]];
// right
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:button
attribute:NSLayoutAttributeTrailing
multiplier:1.0 constant:leftRightMargin]];
lastView= button;
}
// bottom
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.contentView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:lastView
attribute:NSLayoutAttributeBottom
multiplier:1.0 constant:topBottomMargin]];
}
contentView的高度好像是0!但是它的顶部和底部都有限制。应该是这样的:
但是我的代码是这样的。任何帮助都会很棒。
由于您在 contentView 上使用自动布局约束,它的高度(框架)在 viewDidLoad 方法中将为零。您应该将您的代码移动到 viewDidLayoutSubviews
方法中并尝试在那里添加您的按钮。
你应该在那里得到 contentView 的高度。如果可行,请告诉我。希望这有帮助。
参考这个问题:iOS AutoLayout - get frame size width
您可以向容器视图添加约束以将视图滚动为等高和等宽。此外,当您向按钮添加约束时,不要忘记向按钮添加底部约束,因为它将决定滚动视图的结束(内容大小)。
我不认为我们不能将自动布局直接添加到 ScrollView 内部的 ContainerView 中,并将 Intrinsic Size 作为默认值,因此我以编程方式将 ContainerView 添加为子视图:
- (void)viewDidLoad{
[super viewDidLoad];
self.contentView = [[UIView alloc] initWithFrame:CGRectZero];
[self.scrollView addSubview:self.contentView];
//Then add your button here as normal.
//...
}
Gurtej Singh 是对的,我们必须更新 viewDidLayoutSubviews 中的框架:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
//Don't for get to update your self.scrollView.contentSize if you want to able to scroll
//...
//Update your contentView frame based on scrollview frame and self.scrollView.contentSize.
self.contentView.frame = self.scrollView.bounds or ....;
}
我只是想帮忙,这可能不是一个好的解决方案,但它对我有用。
我找到了我一直在寻找的解决方案 here:
[super viewDidLoad];
UIScrollView* sv = [UIScrollView new];
sv.backgroundColor = [UIColor whiteColor];
sv.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:sv];
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[sv]|"
options:0 metrics:nil
views:@{@"sv":sv}]];
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[sv]|"
options:0 metrics:nil
views:@{@"sv":sv}]];
UILabel* previousLab = nil;
for (int i=0; i<30; i++) {
UILabel* lab = [UILabel new];
lab.translatesAutoresizingMaskIntoConstraints = NO;
lab.text = [NSString stringWithFormat:@"This is label %i", i+1];
[sv addSubview:lab];
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[lab]"
options:0 metrics:nil
views:@{@"lab":lab}]];
if (!previousLab) { // first one, pin to top
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[lab]"
options:0 metrics:nil
views:@{@"lab":lab}]];
} else { // all others, pin to previous
[sv addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[prev]-(10)-[lab]"
options:0 metrics:nil
views:@{@"lab":lab, @"prev":previousLab}]];
}
previousLab = lab;
}
// last one, pin to bottom and right, this dictates content size height
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:[lab]-(10)-|"
options:0 metrics:nil
views:@{@"lab":previousLab}]];
[sv addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:[lab]-(10)-|"
options:0 metrics:nil
views:@{@"lab":previousLab}]];
// look, Ma, no contentSize!