之前一直在吐槽iOS的布局方式(frame和autolayout)相比前端的flex布局方式很落后,也在想有没有其它的方式来改善。最近偶然发现UIStackView的存在(苹果爸爸原谅我😂),了解后发现其中的使用与布局方式类似于flex布局,感觉这就是苹果爸爸借鉴flex布局特点所构造的一种布局实现方式吧。
实现方式
这里我们看一下如何简单的使用stackview来创造一个拥有众多子item的水平视图。代码如下:
- (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没有大的区别,使用时根绝需要来设置stackView的axis(布局方向)
,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
。
其中完整方法如下:
初始化数组:
- (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数组的最后一个视图,可以用如下方式:
//removeArrangedSubview, 只会把子控件从arrangedSubviews数组中移除,
//不会从subviews中移除,如果需要可调用removeFromSuperview
UIView *view = [_containerView.subviews lastObject];
[_containerView removeArrangedSubview:view];
[view removeFromSuperview];
到此stackView的一个简单使用方式就知道了。