Fork me on GitHub

(转)UIStackView的简单使用与理解

之前一直在吐槽iOS的布局方式(frame和autolayout)相比前端的flex布局方式很落后,也在想有没有其它的方式来改善。最近偶然发现UIStackView的存在(苹果爸爸原谅我😂),了解后发现其中的使用与布局方式类似于flex布局,感觉这就是苹果爸爸借鉴flex布局特点所构造的一种布局实现方式吧。

实现方式

这里我们看一下如何简单的使用stackview来创造一个拥有众多子item的水平视图。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

containerView = [[UIStackView alloc]initWithFrame:CGRectMake(0, 100, CGRectGetWidth(self.view.bounds), 200)];
//子视图布局方向:水平或垂直
containerView.axis = UILayoutConstraintAxisHorizontal;//水平布局
//子控件依据何种规矩布局
containerView.distribution = UIStackViewDistributionFillEqually;//子控件均分
//子控件之间的最小间距
containerView.spacing = 10;
//子控件的对齐方式
containerView.alignment = UIStackViewAlignmentFill;
NSArray *tempArray = @[@"1",@"2",@"3",@"4"];
for (NSInteger i = 0; i < 4; i++) {
// UIView *view = [[UIView alloc]init];
UILabel *label = [[UILabel alloc] init];
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor colorWithRed:random()%256/255.0 green:random()%256/255.0 blue:random()%256/255.0 alpha:1];
label.numberOfLines = 0;
label.text = tempArray[i];

[containerView addArrangedSubview:label];

}
[self.view addSubview:containerView];
}

可以看到 stackView 的使用和view没有大的区别,使用时根绝需要来设置 stackViewaxis(布局方向), distribution(子控件依据何种规矩布局), spacing(子控件之间的最小间距), alignment(子控件的对齐方式)等属性。


属性及方法

这里详细说明一下个属性的主要参数:

axis:

子控件的布局方向,水平( UILayoutConstraintAxisHorizontal)或垂直(UILayoutConstraintAxisVertical), 这个不用过多解释了

UIStackViewDistribution

UIStackViewDistributionFill :它就是将 arrangedSubviews 填充满整个 StackView ,如果设置了spacing,那么这些 arrangedSubviews 之间的间距就是spacing。如果减去所有的spacing,所有的 arrangedSubview 的固有尺寸( intrinsicContentSize )不能填满或者超出 StackView 的尺寸,那就会按照 Hugging 或者 CompressionResistance 的优先级来拉伸或压缩一些 arrangedSubview 。如果出现优先级相同的情况,就按排列顺序来拉伸或压缩。

UIStackViewDistributionFillEqually :这种就是 StackView 的尺寸减去所有的spacing之后均分给 arrangedSubviews ,每个 arrangedSubview 的尺寸是相同的。

UIStackViewDistributionFillProportionally :这种跟FillEqually差不多,只不过这个不是讲尺寸均分给 arrangedSubviews ,而是根据 arrangedSubviews 的 intrinsicContentSize 按比例分配。

UIStackViewDistributionEqualSpacing :这种是使 arrangedSubview 之间的spacing相等,但是这个spacing是有可能大于 StackView 所设置的spacing,但是绝对不会小于。这个类型的布局可以这样理解,先按所有的 arrangedSubview 的 intrinsicContentSize 布局,然后余下的空间均分为spacing,如果大约 StackView 设置的spacing那这样就OK了,如果小于就按照 StackView 设置的spacing,然后按照 CompressionResistance 的优先级来压缩一个 arrangedSubview 。

UIStackViewDistributionEqualCentering :这种是使 arrangedSubview 的中心点之间的距离相等,这样没两个 arrangedSubview 之间的spacing就有可能不是相等的,但是这个spacing仍然是大于等于 StackView 设置的spacing的,不会是小于。这个类型布局仍然是如果 StackView 有多余的空间会均分给 arrangedSubviews 之间的spacing,如果空间不够那就按照 CompressionResistance 的优先级压缩 arrangedSubview 。

alignment

UIStackViewAlignmentFill = 默认方式, 如果子控件水平布局, 则指子控件的垂直方向填充满stackView. 反之亦然

UIStackViewAlignmentLeading = 如果子控件竖直布局, 则指子控件左边对齐stackView左边. 反之亦然, 即 UIStackViewAlignmentTop = UIStackViewAlignmentLeading。

UIStackViewAlignmentTop = UIStackViewAlignmentLeading,

UIStackViewAlignmentFirstBaseline = 根据上方基线布局所有子视图的 y 值(适用于 Horizontal 模式)

UIStackViewAlignmentLastBaseline = 根据下方基线布局所有子视图的 y 值(适用于 Horizontal 模式)

UIStackViewAlignmentCenter = 中心对齐

UIStackViewAlignmentTrailing = 如果子控件竖直布局, 则指子控件左边对齐stackView右边. 反之亦然, 即UIStackViewAlignmentBottom = UIStackViewAlignmentTrailing

UIStackViewAlignmentBottom = UIStackViewAlignmentTrailing

方法

这里还要说明几个方法:addArrangedSubview、removeArrangedSubview和insertArrangedSubview,日常view的添加和子视图从复视图删除使用的是addSubview和removeFromSuperview。

其中完整方法如下:

1
2
3
4
5
6
7
8
初始化数组:
- (instancetype)initWithArrangedSubviews:(NSArray *)views;
添加子视图:
- (void)addArrangedSubview:(UIView *)view;
移除子视图:
- (void)removeArrangedSubview:(UIView *)view;
根据下标插入视图:
- (void)insertArrangedSubview:(UIView *)viewatIndex:(NSUInteger)stackIndex;

注意

注意: addArrangedSubview 和 insertArrangedSubview, 会把子控件加到arrangedSubviews数组的同时添加到StackView的subView数组中,但是removeArrangedSubview, 只会把子控件从arrangedSubviews数组中移除,不会从subviews中移除,如果需要调用removeFromSuperview


若我们需要删除stackView中subView数组的最后一个视图,可以用如下方式:

1
2
3
4
5
//removeArrangedSubview, 只会把子控件从arrangedSubviews数组中移除,
//不会从subviews中移除,如果需要可调用removeFromSuperview
UIView *view = [_containerView.subviews lastObject];
[_containerView removeArrangedSubview:view];
[view removeFromSuperview];

到此stackView的一个简单使用方式就知道了。

- END -
关注微信公众号,发现更多精彩

文章作者:梁大红

特别声明:若无特殊声明均为原创,转载请注明,侵权请联系

版权声明:署名-非商业性使用-禁止演绎 4.0 国际