0


UIStackView使用进阶

01

技术背景

前端的布局方式比较灵活,提供有

Flex

的布局方式,可以实现不同方向的弹性布局。

Flex

就像一个容器,可以将其内部的子控件统一进行布局。其包含主轴方向和交叉轴方向,主轴方向表示控件的排布方向,交叉轴方向和主轴方向相垂直。熟悉前端

Flex

控件的同学应该知道。

Flex

有一些常用属性,这里对其进行简单介绍,方便了解

UIStackView

的技术背景。

  • flex-direction:控制Flex的方向,垂直还是水平;
  • flex-wrap:是否允许换行显示,nowrap表示单行显示,nowarp的场景下,如果控件过多,则可能导致子项等比缩小的问题;
  • justify-content:决定Flex主轴方向上,子项对齐和分布方式,例如从前到后排列,或者等间距分布等;
  • align-items:决定Flex交叉轴方向上,子项的对齐和分布方式,例如主轴设置为row,交叉轴flex-start就表示顶对齐,center表示垂直居中对齐;
  • align-content:作用于交叉轴方向每行的对齐方式,属性只针对于有换行的场景下有效。例如flex-start是从上到下逐行排列,space-between则表示每行间距相同,平均分配每行之间间距。

02

UIStackView介绍

在介绍完

Flex

布局的背景之后,这里讲一下

UIStackView

控件。在

ios9

中苹果在

UIKit

框架中引入了一个新的视图类

UIStackView

UIStackView

借鉴了

Flex

的布局思想,采用线性布局的方式,统一对子视图进行布局。只需要写很少的

Masonry

布局代码,或者不写布局代码即可完成布局。

UIStackView

已经推出有一些年了,这里介绍这个控件,主要是出于两个目的。一方面是对于没使用过的同学,介绍这个控件的功能以及适用的场景,项目中的一些场景通过

UIStackView

处理起来会轻松很多。另一方面对于已经使用过的同学,我会在文章中讲一些我踩过的坑,以帮助大家更好的使用这个控件来解决业务中的问题。

需要注意的是,

UIStackView

虽然继承自

UIView

,但是并不参与屏幕的渲染,所以重写

drawRect:

方法也是无效的。

03

核心参数

UIStackView

提供了两个方向的布局,垂直布局和水平布局,我们可以通过

UILayoutConstraintAxis

枚举值进行设置。如果初学者来学习

UIStackView

比较抽象,不太好接触这个新的控件,而且很容易出错,先看一下下面这个

gif

来初步了解一下这个控件。

4da3382fccfae9d7df35e1334cd3a706.gif

下面是一些

UIStackView

的核心参数。

1、轴

  • horizontal:水平方向布局
  • vertical:垂直方向布局

bb065bee91d0391896d79446c9d9e5ee.jpeg

2、分配

  • fill:填充整个UIStackView,并且根据内部子视图尺寸进行动态调整,可能会拉伸或压缩某个子视图,可以通过ContentHuggingPriorityContentCompressionResistancePriority控制拉伸和压缩的视图,后面会讲到。

f8d29fef857955822e3fee9dc1227f3d.jpeg

  • fillEqually:子视图等宽或等高,填充整个stackView,过程中会根据分配的大小改变子视图尺寸。

386ea9c155f3fe092e46a238f9bccca0.jpeg

  • fillProportionally:根据子视图intrinsicContentSize按比例布局。![9a794741d5a44e5075557b38f5ac9dd1.jpeg](https://img-blog.csdnimg.cn/img_convert/9a794741d5a44e5075557b38f5ac9dd1.jpeg)

  • equalSpacing:等间距布局,如果stackView放不下则会对子视图进行压缩,默认压缩最后加入的子视图。0609a10cacddc261b66a3d1eed863f18.jpeg

  • equalCentering:平均分配子视图得到每个视图的中心点,使用这个中心点来布局每个子视图,并且保持spacing距离,超出stackView将会压缩子视图。![74f160ea549622b717ef2deeb4bb01c9.jpeg](https://img-blog.csdnimg.cn/img_convert/74f160ea549622b717ef2deeb4bb01c9.jpeg)

3、对准

  • fill:交叉轴方向子视图铺满

9fedcdcfd00f7f7fee9b9cfe8517f5d6.jpeg

  • top:子视图顶对其(适用于horizontal布局)

53cbd22f53a8b8d31b3f647c5fef1b1b.jpeg

  • center:子视图居中对齐

ca8aa1ce535031584a72ba9c30f0b0be.jpeg

  • bottom:子视图底对齐(适用于horizontal布局)

a25df3955292d86878744140ecb1114a.jpeg

  • firstBaseline:按照第一个子视图的文字的第一行对齐,并且尽量保证子视图底对齐(适用于horizontal布局)

c15ad9f869801f9e2abf2c6311ab8431.jpeg

  • lastBaseline:按照最后一个子视图的最后一行对齐,并且尽量保证子视图底对齐(适用于horizontal布局)

67e34009e22692d20defaf6710072977.jpeg

  • trailing:子视图右对齐(适用于vertical布局)

1aeebc77a8b263335411474fd3a29840.jpeg

  • leading:子视图左对齐(适用于vertical布局)

b55aa5b8e13968cba07b9f8dbb8b61f0.jpeg

4、间距

子控件之间的最小距离,根据下面的图片结合上面的枚举值联系起来比较好理解。

71a35fa49d5cbd9b7959260143651460.png

08

基础方法

UIStackView

的使用很多人都知道,这里举一个简单的例子,两个

UILabel

中间有一个分割线,并且整体居中对齐。

112f94c92ae92bd80906bbdffbe1f3e1.jpeg

对于传统的

Masonry

布局,需要写不少布局代码,而且为了整体居中,需要在外面包一层

UIView

进行居中的布局。而使用

UIStackView

,布局代码就下面这些,单独给中间的分割线指定个

size

,就是唯一

Masonry

涉及的处理。

[self.stackView addArrangedSubview:self.privacyButton];
[self.stackView addArrangedSubview:self.declareLineView];
[self.stackView addArrangedSubview:self.createContentDeclare];

[self.declareLineView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(Pixel_1, 11.f));
}];

- (UIStackView *)stackView {
    if (!_stackView) {
        _stackView = [[UIStackView alloc] init];
        _stackView.axis = UILayoutConstraintAxisHorizontal;
        _stackView.alignment = UIStackViewAlignmentFill;
        _stackView.spacing = 8;
    }
    return _stackView;
}

需要注意的是,

UIStackView

添加子视图,需要通过下面指定方法进行,否则子视图布局会有问题。调用此方法后就不用再调用

addSubview

方法,移除时直接调用r

emoveFromSuperview

即可。

- (void)addArrangedSubview:(UIView *)view;

09

使用进阶

1、隐藏子视图

上面的布局场景很简单,但如果是下面这种复杂搜索栏的场景,就很适合用

UIStackView

,通常搜索栏中的按钮会要求某些条件下展示,某些条件下隐藏,同样的搜索栏的宽度也是动态变化的。例如未登录时没有搜索栏右侧的

10086

客服电话按钮,搜索栏右侧贴着消息按钮的。

ae3124f2d97443b2c76a0b46066440ef.jpeg

对于这种场景,只需要将

10086

按钮的

hidden

设置为

true

,则可以实现上述效果。

UIStackView

在检测到某个子视图被

hidde

后,则这个子视图不参与占位。

可以通过下面的动画直观的感受下

hidden

的方便。

c451373d8a6cb34f1a724622477089cf.gif

2、抗拉伸、抗挤压

UIStackView

并不能完全替代

Masonry

,除了其自带的布局功能外,还需要处理子视图的

size

、抗拉伸、抗挤压,以及

stackView

其自身的布局处理。下面是两个抗拉伸和抗压缩的

API

设置抗拉伸级别。默认值

250

,控件级别设置越高,越不容易被拉伸。如果不设置优先级,则排在最前的子视图会被拉伸。

- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis;

设置抗压缩级别。默认值

750

,控件级别设置越高,越不容易被压缩。如果不设置优先级,则排在最后的子视图会被压缩。如果修改最后的子视图优先级为

defaultHigh

,系统会找

750

优先级中最后的子视图进行压缩。

- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis;

这里通过一个例子讲一下抗拉伸的业务场景,抗压缩也是同样的道理。假设有一个场景,一个

horizontal

stackView

有两个

UILabel

,这两个

label

的文案都是动态下发的,产品需求是左侧自适应展示标签文案,右侧文案展示不下打点。

f6c5143fe305d109990c8ab1466ca833.jpeg

这种场景如果用布局来做会很复杂,增加很多计算操作。用

UIStackView

实现就很简单,我们需要保证的是不拉伸左侧

label

,只需要给左边

label

设置抗拉伸优先级高一些即可实现。

tagLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)

10

不足点

相对于前端的

Flex

布局,

UIStackView

对某个子视图可做的处理很有限。

Flex

除了可以对容器自身进行布局设置,即开头介绍的部分,也可以对

Flex

布局中的子视图进行单独布局设置。下面是一些

Flex

对子视图的一些实用属性,可以了解下。

  • orderFlex的每个子视图order默认都是0,如果想让某个视图排列在最前面,可以将order设置为-1,同样的,如果想让子视图展示在最后,可以将order设置为1
  • flex-grow:可以设置某个子视图的扩展,扩展指的是这个子视图是否占据除元素外的空白区域,取值范围是01,例如设置1为则表示占据全部空白区域;
  • flex-basis:通过这个属性可以设置某个子视图占据多少宽度,默认是auto由浏览器分配宽度,如果设置的宽度超过父视图,则子视图会进行等比收缩。
标签:

本文转载自: https://blog.csdn.net/SOHU_TECH/article/details/143612788
版权归原作者 搜狐技术产品小编2023 所有, 如有侵权,请联系我们删除。

“UIStackView使用进阶”的评论:

还没有评论