拥抱 UIStackView

前言

  作为 iOS 开发者,难免会遇到一些 “一个 View 需要基于另一个 View 的消失或出现变更约束”的需求。我之前的做法是选择用 Masnory 将两个约束手动设置成 deactivateactivate,在需要的时候变更属性就可以达到。或者使用约束优先级来做,不过约束优先级就不能只依靠 hidden 属性了,需要的可能是 removefromsuperView

  苹果在 iOS 9 之后推出了 UIStackView,它可以实现上述需求的自动化处理,让我们的代码更加简洁易读。之前因为开发者们向下兼容版本的原则导致运用的并不太多,但是随着现在 iOS 13 的发布,开发者们也都开始逐步放弃兼容 iOS 8了。这就意味着我们可以随心所欲的在我们的项目中使用 UIStackView 了 。

关于 UIStackView

  UIStackViewUIView的子类,只有它并不能达到呈现视图的效果,我们要做的是把控件放入stackView里,让它来帮助我们管理这些控件的约束。

  stackView有两种方式可以使用,一就是使用StoryBoard拖入一个stackView,二是使用代码布局加入UIStackView,并addArrangeView控件来达到约束效果。

  因为平时使用的代码进行布局而非StoryBoard,所以本文会以代码的角度来走进UIStackView

UIStackView 的属性

  • Axis: 将stackView里的子视图设置成垂直布局或水平布局
  • Alignment: 子视图对齐方式
  • Distribution: 子视图的分布比例
  • Spacing: 子视图间距

stackView属性

Axis

  Axis 属性从他的名字和他的值verticalhorizontal就可以看出他是决定stackView轴线的属性。

  • vertical: 使 stackView 里的对象垂直排列

  • horizontal: 使 stackView 里的对象水平排列

Alignment

  Alignment属性的值就有些多了,根据设置它的值,来决定子视图的摆放样式。

Fill

  Fill属性使子视图填满stackViewVertical模式时则是子视图宽填满,Horizontal模式的时候是子视图高填满。

Fill

Leading

  使Vertical模式下的子视图向左对齐,相当于Horizontal模式下的top对齐模式旋转90°。

Leading

Top

  使Horizontal模式下的子视图顶部对齐。

Top

FirstBaseline

  使子视图根据第一个子视图文字的第一行对齐(只在Horizontal模式下生效)

FirstBaseline

LastBaseline

  使子视图根据首个子视图文字的最后一行对齐(只在Horizontal模式下生效)

LastBaseLine

Center

  使子视图中央对齐

Center

Trailing

  Vertical模式下的子视图尾部(右侧)对齐

Trailing

Bottom

  Horizontal模式下子视图尾部(下方)对齐

Alignment_Bottom

Distribution

  属性作用于子视图上,用于子视图的布局

Fill

  使子视图的宽/高(根据Axis决定)充满stackView,它会优先压缩hugging优先级低的子视图。

DistributionFill

FillEqually

  使子视图的宽/高(根据Axis决定)相等排列,所有子视图都会被拉伸或压缩。

DistributionFillEqually

FillPropoetionally

  根据子视图的比例来拉伸或压缩宽/高。如Horizontal下的三个子视图的宽度比是 1:2:3 ,那根据stackView的大小,子视图会被拉伸或者压缩,但是他们的宽度比始终是 1:2:3

DistributionFillProportionally

EqualSpacing

  使子视图根据 spacing 等距排列。

DistributionEqualSpacing

EqualCentring

  使子视图的中心点之间的距离保持一致,有点类似于EqualSpacing

DistributionEqualCentering

UIStackView的使用

  stackView的使用非常方便,只需要在初始化的时候设置上文的属性,并且将子视图addArrangedSubviewstackView就可以实现布局了。当一个子视图被removehidden时,在stackView里的其他子视图就会自动调整。

1
2
3
4
5
6
7
// 示例
UIStackView *stackView = [[UIStackView alloc] init];
stackView.alignment = UIStackViewAlignmentLeading;
stackView.axis = UILayoutConstraintAxisVertical;
stackView.spacing = 2;
[stackView addArrangedSubView:View1];
[stackView addArrangedSubView:View2]; // View2会显示在View1的下方且间隔为2

  熟悉了stackView的使用之后,我们会发现我们大多数用stackView都是用于解决等距排列的需求。

  但我们偶尔还会遇到一些子视图之间间隔不等但还需要自动排列控件的情况,这种需求我们第一选择可能不会使用stackView

  事实上,stackView里还有一个setCustomSpacing:afterView:方法,用来设置某个特定 View 以后的间隔,来达到控件不同间隔的效果。但是这个方法只在iOS 11以上的系统才能生效,所以现有情况下,我们可以使用空白的 View 去填充一些空白,来达到子视图之间间隔不相同的效果。

后记

  UIStackView是苹果公司很早就退出的一套约束管理控件,但是因为兼容系统版本的问题,我们迟迟没有全面用上。但是现在已经是iOS 13的时代了,我们完全可以张开双手,去拥抱stackView,让我们的代码更加简洁有效。

  同时希望Swift UI普及的那一天快一点到来。