浅谈UIStackView

8,478 阅读5分钟

参考文章UIStackView Tutorial: Introducing Stack Views

简介

最近从同事那里了解到UIStackView这个API,之前使用到的自动布局有代码自动布局(Masonary)和拖 constraint 这两种。UIStackView和这两种相比可以减少重复繁琐的工作,使自动布局变得方便快捷。

UIStackView是苹果推出的一套可以自动布局的API,适配iOS9.0之后,iOS8.0之前的不支持,UIStackView是一个容器,UIStackView继承自UIView,但是它本身不能自我渲染,比如为他设置 backgroundColor 是无效的,所以它要和 UIView 相辅相成的进行工作。它能够帮助 UIView 来处理 子视图 的位置和大小等布局问题。他的定位是介于 手写约束 和 UITableView/UICollectionView 之间的工具。

UIStackView一般用于实现水平平铺一行或者垂直平铺一行的视图组合。

哈哈哈

正文

1、UIStackView的初始化

用一个简图表示一下UIStackView和父视图以及子视图之间的继承关系

代码初始化一个stackView并添加到父视图上

- (void)initStackView{
    self.stackView = [[UIStackView alloc] init];
    self.stackView.axis = UILayoutConstraintAxisHorizontal;
    self.stackView.distribution = UIStackViewDistributionFill;
    self.stackView.spacing = 10;
    self.stackView.alignment = UIStackViewAlignmentFill;
    self.stackView.frame = CGRectMake(0, 100, ScreenWidth, 200);
    [self.view addSubview:self.stackView];
}

2、 UIStackView的一些属性

2.1 axis(轴向) 属性

决定了 stack 的朝向,只有垂直或水平;

typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {
UILayoutConstraintAxisHorizontal = 0,//水平布局方向
UILayoutConstraintAxisVertical = 1//垂直布局方向
};

2.2 distribution(分布) 属性

描述了其管理的子视图在沿着其轴向(axis)上的布局关系;

typedef NS_ENUM(NSInteger, UIStackViewDistribution) {
UIStackViewDistributionFill = 0, 
UIStackViewDistributionFillEqually,
UIStackViewDistributionFillProportionally,
UIStackViewDistributionEqualSpacing,
UIStackViewDistributionEqualCentering,
} NS_ENUM_AVAILABLE_IOS(9_0);

  • 2.2.1 UIStackViewDistributionFill

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

UIStackViewDistributionFill

  • 2.2.2 UIStackViewDistributionFillEqually

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

UIStackViewDistributionFillEqually

  • 2.2.3 UIStackViewDistributionFillProportionally

这个和FillEqually差不多,只是这个不是将尺寸均分给 arrangedSubviews ,而是根据 arrangedSubviews 的 intrinsicContentSize 按比例分配。

UIStackViewDistributionFillProportionally

  • 2.2.4 UIStackViewDistributionEqualSpacing

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

UIStackViewDistributionEqualSpacing

  • 2.2.5 UIStackViewDistributionEqualCentering

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

UIStackViewDistributionEqualCentering

2.3 alignment(对齐) 属性

决定了其管理的视图在垂直于其轴向上的布局;

typedef NS_ENUM(NSInteger, UIStackViewAlignment) {
UIStackViewAlignmentFill,//子视图填充StackView
UIStackViewAlignmentLeading,//子视图左对齐(axis为垂直方向而言)
UIStackViewAlignmentTop = UIStackViewAlignmentLeading,//子视图顶部对齐(axis为水平方向而言)
UIStackViewAlignmentFirstBaseline, // 按照第一个子视图的文字的第一行对齐,同时保证高度最大的子视图底部对齐(只在axis为水平方向有效)
UIStackViewAlignmentCenter,//子视图居中对齐
UIStackViewAlignmentTrailing,//子视图右对齐(axis为垂直方向而言)
UIStackViewAlignmentBottom = UIStackViewAlignmentTrailing,//子视图底部对齐(axis为水平方向而言)
UIStackViewAlignmentLastBaseline, // 按照最后一个子视图的文字的最后一行对齐,同时保证高度最大的子视图顶部对齐(只在axis为水平方向有效)
} NS_ENUM_AVAILABLE_IOS(9_0);

  • 2.3.1 UIStackViewDistributionFill

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

UIStackViewDistributionFill(axis为水平)

  • 2.3.2 UIStackViewAlignmentLeading

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

UIStackViewAlignmentLeading(axis为竖直)

  • 2.3.3 UIStackViewAlignmentTop

UIStackViewAlignmentTop(axis为水平)

  • 2.3.4 UIStackViewAlignmentFirstBaseline

按照第一个子视图的文字的第一行对齐,同时保证高度最大的子视图底部对齐(只在axis为水平方向有效)

UIStackViewAlignmentFirstBaseline(axis为水平)

  • 2.3.5 UIStackViewAlignmentCenter

子视图居中对齐。

UIStackViewAlignmentCenter(axis为水平)

  • 2.3.6 UIStackViewAlignmentTrailing

子视图右对齐(axis为垂直方向而言)。

UIStackViewAlignmentTrailing(axis为竖直)

  • 2.3.7 UIStackViewAlignmentBottom

axis为水平时UIStackViewAlignmentBottom = UIStackViewAlignmentTrailing。

UIStackViewAlignmentBottom(axis为水平)

  • 2.3.8 UIStackViewAlignmentLastBaseline

按照最后一个子视图的文字的最后一行对齐,同时保证高度最大的子视图顶部对齐(只在axis为水平方向有效)

UIStackViewAlignmentLastBaseline(axis为竖直)

2.4 spacing(空隙) 属性

设置子视图之间的间距,是子视图之间的最小间距,之所以说是最小间距,因为stackView会根据一定的规则对内部空间布局,有的时候不能满足所有要求,比如stackView 本身宽度100,内部两个控件,宽度都为100,100+100+10就超过了本身宽度, 这时会压缩其中一个子控件的宽度来满足最小间距。

2.5 baselineRelativeArrangement 属性(默认为false)

决定了其视图间的垂直间隙是否根据基线测量得到。

2.6 layoutMarginsRelativeArrangement 属性(默认为false)

决定了 stackView 平铺其管理的子视图时是否要参照它的布局边距,如果是YES则通过 layout margins 布局,为NO则通过 bounds布局。

3、UIStackView的一些常用方法

3.1 创建一个Stack视图

-initWithArrangedSubviews: (New in iOS 9.0):初始化子视图数组

3.2 管理子视图

-addArrangedSubview: (New in iOS 9.0): 添加子视图

3.2.2 -arrangedSubviews Property (New in iOS 9.0): UIStackView使用arrangedSubviews数组来管理子视图。

3.2.3 -insertArrangedSubview:atIndex: (New in iOS 9.0):根据下标插入视图

-removeArrangedSubview: (New in iOS 9.0):移除子视图

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

UIStackView的使用示例

附上gitHub demo

工程示例
运行结果

总结

UIStackView可以通过代码或者xib实现,平时工作中一边使用代码实现,代码更方便后期项目的功能修改,更便于维护。学会它的使用能方便我们快速开发新功能。希望能和大家探讨更多关于UIStackView的知识。