为了账号安全,请及时绑定邮箱和手机立即绑定

如何调整超级视图的大小以适合具有自动布局的所有子视图?

如何调整超级视图的大小以适合具有自动布局的所有子视图?

iOS
阿晨1998 2019-12-07 14:54:02
我对自动布局的理解是,它采用了超级视图的大小,并基于约束和内在大小来计算子视图的位置。有没有办法扭转这个过程?我想基于约束和内在大小调整Superview的大小。最简单的方法是什么?我在Xcode中设计了视图,将其用作的标题UITableView。该视图包括标签和按钮。标签的大小因数据而异。根据约束,标签可以成功按下按钮,或者如果按钮和超级视图底部之间存在约束,则标签将被压缩。我发现了一些类似的问题,但没有好的和简单的答案。
查看完整描述

3 回答

?
波斯汪

TA贡献1811条经验 获得超4个赞

正确使用的API UIView systemLayoutSizeFittingSize:是UILayoutFittingCompressedSize或传递UILayoutFittingExpandedSize。


对于正常UIView使用自动布局的方法,只要您的约束正确,它就应该起作用。如果要在上使用它UITableViewCell(例如确定行高),则应在单元格上调用它contentView并抓住它的高度。


如果您的视图中有一个或多个多行UILabel,则需要进一步考虑。对于这些,preferredMaxLayoutWidth必须正确设置属性,以使标签提供正确的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:


查看完整回答
反对 回复 2019-12-07
?
MMMHUHU

TA贡献1834条经验 获得超8个赞

为了使视图的大小由放置在其中的内容确定,那么放置在其中的内容必须与包含视图具有显式关系才能驱动其高度(或宽度)动态。“添加子视图”不会创建您可能假定的关系。您必须选择哪个子视图来驱动容器的高度和/或宽度……最常见的是,您在整个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


查看完整回答
反对 回复 2019-12-07
?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

您可以通过创建约束并通过接口构建器将其连接来完成此操作


参见说明:Auto_Layout_Constraints_in_Interface_Builder


raywenderlich开始自动布局


AutolayoutPG文章约束基础


@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

我希望这可以澄清它。


查看完整回答
反对 回复 2019-12-07
  • 3 回答
  • 0 关注
  • 600 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信