前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS AutoLayout全解

iOS AutoLayout全解

作者头像
xiangzhihong
发布2018-02-06 18:58:46
4.4K0
发布2018-02-06 18:58:46
举报
文章被收录于专栏:向治洪向治洪向治洪

AutoLayout简介

Autolayout是一种全新的布局技术,专门用来布局UI界面的,用来取代Frame布局在遇见屏幕尺寸多重多样的问题。Autolayout自iOS 6开始引入, 但是由于Xcode 4的不给力,当时并没有得到大规模推广。在iOS 7(Xcode5)开始,Autolayout的开发效率得到很大的提升,苹果官方也推荐开发者尽量使用Autolayout来布局UI界面,减少纯代码的方式。 那么AutoLayout怎么使用呢?

这里写图片描述
这里写图片描述

VFL

VFL(Virsual Format Language)是一种虚拟的格式化语言,主要用来创建AutoLayout的约束字符串。 示例,如:V: |-(0)-Label1-(0)-Label2-(0)-| 方向:从左到右,从上到下 V:表示方向为垂直方向,也就是竖向;H为横向。 |:竖线表示为边界(当前所在View的边界),这里紧邻方向表示符V,方向是从上到下,因此表示上面界。 0:NSNumber 0 表示约束值为0。这里是Label1距离上边界的约束为0。 Label1:表示对象Label1。 0:表示Label1和Label2的约束为0. Label2:表示对象Label2。 0:表示Label2和下边界的约束为0. |:表示下边界。

关于[VFL官网]详细知识,请查看官方的介绍

AutoLayout IB使用方式

为了让布局能够在不同屏幕的size上都能够表现正常,我们需要对其增加“约束”。然后,在不同屏幕尺寸下view就能够按照约束来局。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

添加如下约束:

这里写图片描述
这里写图片描述
属性说明:
1:距离边缘 最上面的4个虚线表示某个View的距离上边 左边 右边 下边多高
2:那个蓝色的Constrain To Margins 是iPhone6出现之后。
Apple 觉得更大的分辨率有点间距好看, 默认为8 , 如果这个勾上了 这个View距离四周的值就变成了 你输入的值+8。 一般建议勾掉 。

案例1

设置某个View距离父View上下左右间距全部为20。

这里写图片描述
这里写图片描述

案例2

某个View距离父View的左侧20,上20,宽高均为100。

这里写图片描述
这里写图片描述
注意:我在添加约束的时候有个选项叫做updateFrame 如果勾选 会直接将Frame调整到真实值 ,而不需要再次update 。

案例3

某个View距离在父View的左侧20 案例2中白色View 上20 宽高和Demo2中的宽高一样。

这里写图片描述
这里写图片描述

然后,点击某个约束。

这里写图片描述
这里写图片描述

对其处理

这里写图片描述
这里写图片描述

属性说明:

  • Leading Edges:左对齐
  • Trailing Edges:右对齐
  • Top Edges:上对齐
  • Bottom Edges:下对齐
  • Horizontal Centers:水平中心对齐
  • Vertical Centers:竖向中心对齐
  • Baselines:基线对齐
  • Horizontal Center in Container:对齐容器中的水平中心
  • Vertical Center in Container:对齐容器中的竖向中心

案例4

某个View距离在父View的右侧20 案例3中白色View上20 宽高和案例3中的宽高一样 并且对齐。

这里写图片描述
这里写图片描述

案例5

某个label和另外一个label基线对齐。

这里写图片描述
这里写图片描述

像label 默认是有宽度的 宽度就是字体自适应的。这样我们就可以不给UIlabel 高度 把Label的NumberOfline = 0就可以自适应高度了。

这里写图片描述
这里写图片描述

Tip

1,有时候约束太多的时候 我们可以给某个View起个假名字以起到唯一标识的作用。 2,View总是选不中怎么办?按 ctrl + shift + 单击。 3,当ScrollView过长无法编辑怎么办?将控制器改为Freedom 修改ContentView的高度约束 这样ScrollView 就可以滚动了。

这里写图片描述
这里写图片描述

UItableViewCell高度计算

为了方便说明,本部分知识主要从以下几个方面讲解。

  • AutoLayout with UILabel in UITableViewCell
  • AutoLayout with UITextView in UITableViewCell
  • Manual Layout with UILabel in UITableViewCell
  • Manual Layout with UITextView in UITableViewCell
  • 随UITextView高度动态改变Cell高度

AutoLayout with UILabel

创建一个空的xib,命名为C1.xib, 然后拖入一个UITableViewCell控件。接着创建一个UITableViewCell的子类,命名为C1类。然后在C1.xib中,将与C1类进行关联。只需要在Class那里写入关联的类名C1即可。

这里写图片描述
这里写图片描述

还有由于UITableViewCell需要重用功能,所以我们还需要设置一个重用标识。

这里写图片描述
这里写图片描述

下面是使用autoLayout的布局。

这里写图片描述
这里写图片描述

接着我们在UITableView中来使用我们自定义的UITableViewCell C1。首先我们创建一个UITableViewController的子类T1ViewController, 接着在Main.storyboard中拖入一个UITableViewController,并关联T1ViewController。

这里写图片描述
这里写图片描述

Auto Layout with UITextView

同样参考上面我们创建一个C2.xib, UITableViewCell的子类C2,并关联C2.xib与C2类。并在C2.xib中对其布局,同样使用了auto layout. 布局如下图:

这里写图片描述
这里写图片描述

创始UITableViewController的了类T2ViewController,在Main.storyboard中拖入UITableViewController,并关联他们。接着代码中注册C2.xib到UITableView。 如下面是计算UITableView高度的代码:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    C2 *cell = (C2 *)self.prototypeCell;
    cell.t.text = [self.tableData objectAtIndex:indexPath.row];
    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    CGSize textViewSize = [cell.t sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];
    CGFloat h = size.height + textViewSize.height;
    h = h > 89 ? h : 89;  //89是图片显示的最低高度, 见xib
    NSLog(@"h=%f", h);
    return 1 + h;
}

在这儿我们是通过sizeThatFits:计算的UITextView的高度,然后加上systemLayoutSizeFittingSize:返回的高度。为什么要这样呢? 因为UITextView内容的高度不会影响systemLayoutSizeFittingSize计算。 下面是UITextView的实例:

这里写图片描述
这里写图片描述

此图中距顶的约束是10, 距底的约束8, 距左边约束是87,距右边的约束是13, 那么systemLayoutSizeFittingSize:返回的CGSize为height等于19, size等于100. 它UITextView的frame是不影响systemLayoutSizeFittingSize:的计算。所以,我们需要加上textViewSize.height。

Manual Layout with UILabel

按照前面介绍的,我们需要创建C3.xib, C3类, T3ViewController类,Main.storyboard中拖入UITableViewController,并分别建立关联。 为了简单,C3.xib中我就不加padding之类的了,如图:

这里写图片描述
这里写图片描述

然后添加如下的计算代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    C3 *cell = [self.tableView dequeueReusableCellWithIdentifier:@"C3"];
    cell.t.text = [self.tableData objectAtIndex:indexPath.row];
    [cell.t sizeToFit];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    C3 *cell = (C3 *)self.prototypeCell;
    NSString *str = [self.tableData objectAtIndex:indexPath.row];
    cell.t.text = str;
    CGSize s = [str calculateSize:CGSizeMake(cell.t.frame.size.width, FLT_MAX) font:cell.t.font];
    CGFloat defaultHeight = cell.contentView.frame.size.height;
    CGFloat height = s.height > defaultHeight ? s.height : defaultHeight;
    NSLog(@"h=%f", height);
    return 1  + height;
}

这里,用到了一个NSString的Cagetory方法,代码如下:

- (CGSize)calculateSize:(CGSize)size font:(UIFont *)font 
{
    CGSize expectedLabelSize = CGSizeZero;

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
        NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle.copy};

        expectedLabelSize = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
    }
    else {
        expectedLabelSize = [self sizeWithFont:font
                                       constrainedToSize:size
                                           lineBreakMode:NSLineBreakByWordWrapping];
    }

    return CGSizeMake(ceil(expectedLabelSize.width), ceil(expectedLabelSize.height));
}

运行效果如下:

这里写图片描述
这里写图片描述

Manual Layout with UITextView

按照前面介绍的,我们需要创建C4.xib, C4类, T4ViewController类,Main.storyboard中拖入UITableViewController,并分别建立关联。 为了简单,C4.xib中我就不加padding之类的了,如图:

这里写图片描述
这里写图片描述

相关代码如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    C4 *cell = [self.tableView dequeueReusableCellWithIdentifier:@"C4"];
    cell.t.text = [self.tableData objectAtIndex:indexPath.row];
    [cell.t sizeToFit];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    C4 *cell = (C4 *)self.prototypeCell;
    NSString *str = [self.tableData objectAtIndex:indexPath.row];
    cell.t.text = str;
    CGSize s =  [cell.t sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];
    CGFloat defaultHeight = cell.contentView.frame.size.height;
    CGFloat height = s.height > defaultHeight ? s.height : defaultHeight;
    return 1  + height;
}

随UITextView高度改变Cell高度

当UITextView内容改变的时候,计算自身高度,然后通知UITableView更新,这样就会触发UITableViewCell高度重新计算,从而改变Cell的高度。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    C5 *cell = [self.tableView dequeueReusableCellWithIdentifier:@"C5"];
    cell.t.text = @"123";
    cell.t.delegate = self;
    return cell;
}

#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    C5 *cell = (C5 *)self.prototypeCell;
    cell.t.text = self.updatedStr;
    CGSize s =  [cell.t sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];
    CGFloat defaultHeight = cell.contentView.frame.size.height;
    CGFloat height = s.height > defaultHeight ? s.height : defaultHeight;
    return 1  + height;
}

#pragma mark - UITextViewDelegate
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    if ([text isEqualToString:@"\n"]) {
        NSLog(@"h=%f", textView.contentSize.height);
    }
    return YES;
}

- (void)textViewDidChange:(UITextView *)textView {
    self.updatedStr = textView.text;
    [self.tableView beginUpdates];
    [self.tableView endUpdates];
}

关于UITableViewCell使用自动布局的优化可以查看下面的介绍: 优化UITableViewCell高度计算

StackView

UIStackView是iOS9新引入的控件,它支持垂直和水平排列多个子视图(SubView)。例如:水平放置三个按钮,等宽,并且按钮间的间隙为10,如果自己实现会比较麻烦,而使用UIStackView则很容易实现。UIStackView目前只支持iOS9+版本,如果要在iOS 7版本上使用UIStackView,可以使用下面两个第三方库:OAStackViewTZStackView。其中:

  • OAStackView,基于OC的StackView库,支持iOS7+以上的系统,同时支持代码和IB视图。
  • TZStackView,基于Swift的StackView库,同样支持iOS7+以上的系统,但是不支持storyboard。

OAStackView实现子视图等分

案例1

例如,下面的例子是使用OAStackView实现视图等分的例子。

这里写图片描述
这里写图片描述

相关代码如下:

 UILabel *l1 = [[UILabel alloc] init];
 l1.text = @"Label 1";
 UILabel *l2 = [[UILabel alloc] init];
 l2.text = @"Label 2";
 OAStackView *stackView = [[OAStackView alloc] initWithArrangedSubviews:@[l1, l2]];
 stackView.translatesAutoresizingMaskIntoConstraints = NO;
 [self.view addSubview:stackView];
 [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[stackView]"
                                                                  options:0
                                                                  metrics:0
                                                                    views:NSDictionaryOfVariableBindings(stackView)]];
 [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[stackView]"
                                                                  options:0
                                                                  metrics:0
                                                                    views:NSDictionaryOfVariableBindings(stackView)]];

上面的例子实现了两个按钮的垂直排列。如果想要水平排列,修改stackView.axis值为UILayoutConstraintAxisHorizontal即可。需要注意,因为不是用IB创建的View,所以要设定View的translatesAutoresizingMaskIntoConstraints属性为NO,否则排列属性不生效。当非IB创建时,属性默认为YES;当IB创建View时,属性默认为NO。

案例2

在水平方向上放4张图片,图片等分。 1,首先在页面上拖拽1个imageView,将它的宽高都设置成50。

这里写图片描述
这里写图片描述

2,然后再添加三个imageView,将界面上的四个ImageView设置等宽等高。

这里写图片描述
这里写图片描述

3,然后再将他们加入到Stack View中,设置Stack View 的distribution属性为 Equal Spacing(等间距)。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

4,最后,设置Stack View 的位置

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

StackView属性

在理解StackView时,有几个属性需要理解: Axis: 这个属性是改变UIStackView中的排布方式的属性,其中有水平排布与垂直排布

  • Alignment:这个属性是其中子视图的位置摆布方式默认是填充摆布
  • Fill:子视图填充他所在的位置(默认)
  • Leading:子视图头部对齐
  • Center:子视图居中对齐
  • Trailing:子视图尾部对齐
  • Distribution:子视图的大小
  • Fill:子视图填充整个UIStackView
  • Fill Equally:子视图填充空白区域并等分
  • Fill Proportionally:按照目前相对位置进行填充
  • Equal Spacing:等间距
  • Spacing设置子视图之间的间距大小
  • Baseline Relative:如果设置子视图间距的大小为基线到下一个视图的头部
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-09-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AutoLayout简介
    • VFL
      • AutoLayout IB使用方式
        • 案例1
        • 案例2
        • 案例3
        • 对其处理
        • 案例4
        • 案例5
      • Tip
      • UItableViewCell高度计算
        • AutoLayout with UILabel
          • Auto Layout with UITextView
            • Manual Layout with UILabel
              • Manual Layout with UITextView
                • 随UITextView高度改变Cell高度
                • StackView
                  • OAStackView实现子视图等分
                    • 案例1
                    • 案例2
                  • StackView属性
                  相关产品与服务
                  容器服务
                  腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档