如何调整大小,以适应所有子视图与自动布局?

我对自动布局的理解是,它采用了视图的大小,并根据约束和内部大小计算子视图的位置。

有办法逆转这个过程吗?我希望根据约束和内部大小调整“管理视图”的大小。实现这一目标的最简单方法是什么?

我有在 Xcode 设计的视图,我用它作为 abc 0的标题。这个视图包括一个标签和一个按钮。标签的大小取决于数据。根据约束,标签成功地按下按钮,或者如果有一个约束之间的按钮和底部的管理视图的标签被压缩。

我发现了一些类似的问题,但它们都没有简单明了的答案。

111809 次浏览

你可以通过创建一个约束并通过 Interface Builder 连接它来实现这一点

见解释: Auto _ Layout _ Constraint _ in _ Interface _ Builder

Raywenderlich 开始-自动布局

文章约束基础

@interface ViewController : UIViewController {
IBOutlet NSLayoutConstraint *leadingSpaceConstraint;
IBOutlet NSLayoutConstraint *topSpaceConstraint;
}
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leadingSpaceConstraint;

连接此约束出口与您的子视图约束或连接超级视图约束,并设置它根据您的要求,如下所示

 self.leadingSpaceConstraint.constant = 10.0;//whatever you want to assign

我希望这能澄清一切。

这可以做一个正常的 subview内一个较大的 UIView,但它不会自动工作的 headerViewsheaderView的高度是由 tableView:heightForHeaderInSection:返回的值决定的,所以你必须根据 UILabelheight加上 UIButton和任何你需要的 padding的空间来计算 height。你需要这样做:

-(CGFloat)tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section {
NSString *s = self.headeString[indexPath.section];
CGSize size = [s sizeWithFont:[UIFont systemFontOfSize:17]
constrainedToSize:CGSizeMake(281, CGFLOAT_MAX)
lineBreakMode:NSLineBreakByWordWrapping];
return size.height + 60;
}

这里的 headerString是您想要填充 UILabel的任何字符串,而281号是 UILabelwidth(在 Interface Builder中设置)

正确使用的 API 是 UIView systemLayoutSizeFittingSize:,传递 UILayoutFittingCompressedSizeUILayoutFittingExpandedSize

对于一个正常的 UIView使用自动布局,这应该只要你的约束是正确的。如果您想在 UITableViewCell上使用它(例如确定行高度) ,那么您应该在单元格 contentView上调用它并获取高度。

如果视图中有一个或多个多行 UILabel,则需要进一步考虑。对于这些,正确设置 preferredMaxLayoutWidth属性以使标签提供正确的 intrinsicContentSize是非常重要的,intrinsicContentSize将用于 systemLayoutSizeFittingSize's计算。

编辑: 根据请求,添加表视图单元格的高度计算示例

使用自动布局来计算表单元格的高度并不是非常有效,但是它确实非常方便,特别是当您的单元格具有复杂的布局时。

如上所述,如果您使用的是多行 UILabel,那么必须将 preferredMaxLayoutWidth与标签宽度同步。我使用一个定制的 UILabel子类来完成这项工作:

@implementation TSLabel


- (void) layoutSubviews
{
[super layoutSubviews];


if ( self.numberOfLines == 0 )
{
if ( self.preferredMaxLayoutWidth != self.frame.size.width )
{
self.preferredMaxLayoutWidth = self.frame.size.width;
[self setNeedsUpdateConstraints];
}
}
}


- (CGSize) intrinsicContentSize
{
CGSize s = [super intrinsicContentSize];


if ( self.numberOfLines == 0 )
{
// found out that sometimes intrinsicContentSize is 1pt too short!
s.height += 1;
}


return s;
}


@end

下面是一个人造的 UITableViewController 子类,它演示了 heightForRowAtIndexPath:

#import "TSTableViewController.h"
#import "TSTableViewCell.h"


@implementation TSTableViewController


- (NSString*) cellText
{
return @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
}


#pragma mark - Table view data source


- (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView
{
return 1;
}


- (NSInteger) tableView: (UITableView *)tableView numberOfRowsInSection: (NSInteger) section
{
return 1;
}


- (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath
{
static TSTableViewCell *sizingCell;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{


sizingCell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell"];
});


// configure the cell
sizingCell.text = self.cellText;


// force layout
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];


// get the fitting size
CGSize s = [sizingCell.contentView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];
NSLog( @"fittingSize: %@", NSStringFromCGSize( s ));


return s.height;
}


- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
TSTableViewCell *cell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell" ];


cell.text = self.cellText;


return cell;
}


@end

一个简单的自定义单元格:

#import "TSTableViewCell.h"
#import "TSLabel.h"


@implementation TSTableViewCell
{
IBOutlet TSLabel* _label;
}


- (void) setText: (NSString *) text
{
_label.text = text;
}


@end

这是故事板中定义的约束的图片。注意,标签上没有高度/宽度限制——这些限制是从标签的 intrinsicContentSize推断出来的:

enter image description here

埃里克 · 贝克的评论让我意识到 为了使视图的大小由放置在其中的内容决定,那么放置在其中的内容必须与包含视图有明确的关系,以便动态驱动其高度(或宽度)的核心思想。“添加子视图”不会像您假设的那样创建这种关系。您必须选择哪个子视图将驱动容器的高度和/或宽度... ... 最常见的是您放置在整个 UI 的右下角的任何 UI 元素。下面是一些代码和内联注释来说明这一点。

注意,对于那些使用滚动视图的人来说,这可能有特殊的价值,因为通常围绕一个内容视图进行设计,这个内容视图根据您放入的内容动态地确定其大小(并将其传递给滚动视图)。祝你好运,希望这能帮到别人。

//
//  ViewController.m
//  AutoLayoutDynamicVerticalContainerHeight
//


#import "ViewController.h"


@interface ViewController ()
@property (strong, nonatomic) UIView *contentView;
@property (strong, nonatomic) UILabel *myLabel;
@property (strong, nonatomic) UILabel *myOtherLabel;
@end


@implementation ViewController


- (void)viewDidLoad
{
// INVOKE SUPER
[super viewDidLoad];


// INIT ALL REQUIRED UI ELEMENTS
self.contentView = [[UIView alloc] init];
self.myLabel = [[UILabel alloc] init];
self.myOtherLabel = [[UILabel alloc] init];
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_contentView, _myLabel, _myOtherLabel);


// TURN AUTO LAYOUT ON FOR EACH ONE OF THEM
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
self.myLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.myOtherLabel.translatesAutoresizingMaskIntoConstraints = NO;


// ESTABLISH VIEW HIERARCHY
[self.view addSubview:self.contentView]; // View adds content view
[self.contentView addSubview:self.myLabel]; // Content view adds my label (and all other UI... what's added here drives the container height (and width))
[self.contentView addSubview:self.myOtherLabel];


// LAYOUT


// Layout CONTENT VIEW (Pinned to left, top. Note, it expects to get its vertical height (and horizontal width) dynamically based on whatever is placed within).
// Note, if you don't want horizontal width to be driven by content, just pin left AND right to superview.
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_contentView]" options:0 metrics:0 views:viewsDictionary]]; // Only pinned to left, no horizontal width yet
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_contentView]" options:0 metrics:0 views:viewsDictionary]]; // Only pinned to top, no vertical height yet


/* WHATEVER WE ADD NEXT NEEDS TO EXPLICITLY "PUSH OUT ON" THE CONTAINING CONTENT VIEW SO THAT OUR CONTENT DYNAMICALLY DETERMINES THE SIZE OF THE CONTAINING VIEW */
// ^To me this is what's weird... but okay once you understand...


// Layout MY LABEL (Anchor to upper left with default margin, width and height are dynamic based on text, font, etc (i.e. UILabel has an intrinsicContentSize))
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_myLabel]" options:0 metrics:0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_myLabel]" options:0 metrics:0 views:viewsDictionary]];


// Layout MY OTHER LABEL (Anchored by vertical space to the sibling label that comes before it)
// Note, this is the view that we are choosing to use to drive the height (and width) of our container...


// The LAST "|" character is KEY, it's what drives the WIDTH of contentView (red color)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_myOtherLabel]-|" options:0 metrics:0 views:viewsDictionary]];


// Again, the LAST "|" character is KEY, it's what drives the HEIGHT of contentView (red color)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_myLabel]-[_myOtherLabel]-|" options:0 metrics:0 views:viewsDictionary]];


// COLOR VIEWS
self.view.backgroundColor = [UIColor purpleColor];
self.contentView.backgroundColor = [UIColor redColor];
self.myLabel.backgroundColor = [UIColor orangeColor];
self.myOtherLabel.backgroundColor = [UIColor greenColor];


// CONFIGURE VIEWS


// Configure MY LABEL
self.myLabel.text = @"HELLO WORLD\nLine 2\nLine 3, yo";
self.myLabel.numberOfLines = 0; // Let it flow


// Configure MY OTHER LABEL
self.myOtherLabel.text = @"My OTHER label... This\nis the UI element I'm\narbitrarily choosing\nto drive the width and height\nof the container (the red view)";
self.myOtherLabel.numberOfLines = 0;
self.myOtherLabel.font = [UIFont systemFontOfSize:21];
}


@end

How to resize superview to fit all subviews with autolayout.png