纯代码布局,也可以一样的简洁

语言: CN / TW / HK

theme: juejin highlight: xcode


“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情

前言

在前两篇文章讲述了UIStackView布局思想,使用方法以及一些实用的案例,在案例中使用xib结合UIStackView,缺少一些对纯代码的补充,这篇文章,我们主要聊聊如何使用StackView来写纯代码布局。

即便说过很多StackView的好,但是还是很多人认为复杂的页面用不上,其实真正理解了StackView的布局思想,不管是结构层级简单的布局亦或者复杂的布局,也不管是使用Inferface Builder来构建UI,还是使用纯代码,都能够游刃有余。

下面,我会使用swift演示使用纯代码是怎样布局的。如果有兴趣,点击下载Demo查看效果。下面所展示的代码只是截取的布局部分。

简单布局

简单布局,我归纳为,一行或者一列的元素组成的。通常有类页面如设置页、通讯录。如下布局中,一个hStack包含了image、label、button,组成了一个简单的布局。

结构如下:\ HStack: image + label + Button

swift /// 懒加载 private lazy var vStack = VStack(spacing: 16)

Note: 这里的VStack实际上是对UIStackView的封装以及添加了便携式的初始化,并不是SwiftUIVStack

```swift /// 布局代码 addSubview(hStack) hStack.snp.makeConstraints { make in make.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)) }

/// 这里是使用的扩展方法 iconView.sizeConstraint = CGSize(width: 40, height: 40) title.heightConstraint = 30 follow.sizeConstraint = CGSize(width: 60, height: 30) hStack.addArrangedSubviewsMakeConstraint([iconView, title, hStack.spacer(), follow]) ```

NotesizeConstraint、heightConstraint、widthConstraint、addArrangedSubviewsMakeConstraint、spacer()这些都是自己添加分类方法。

嵌套布局

嵌套布局,我归纳为,界面的元素多样化,需要使用两个以上StackView的布局(不同排列方向)。

结构如下:\ HStack:image + VStack + Button\ VStack:label + label

swift /// 懒加载 private lazy var hStack = HStack(spacing: 8, alignment: .center, distribution: .fill) private lazy var vStack = VStack(spacing: 4, alignment: .fill, distribution: .fill)

Noteswift可以写出比OC更多的语法糖,这是语法的特性所在。从初始化方法上就可以看出。

```swift addSubview(hStack) hStack.snp.makeConstraints { make in make.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)) }

iconView.sizeConstraint = CGSize(width: 50, height: 50) helpView.sizeConstraint = CGSize(width: 30, height: 30) hStack.addArrangedSubviewsMakeConstraint([iconView, vStack, hStack.spacer(), helpView]) vStack.addArrangedSubviews([title, detail]) ```

动态更新布局

动态更新布局,我归纳为,界面的元素多样化,一些界面上的元素会有种状态,继而影响到其他的元素,最终会影响到整体的布局。

结构如下:\ HStack:image + VStack + Button\ VStack:HStack + label\ HStack:label + label

其实整体的布局,与上面的例子中仅仅只有细微的差别,这里想要体现的是,修改stackView的属性以及修改stackView中的排列视图的width、height或者hidden相关的属性,都会使stackView重新布局。

```swift private lazy var hStack = HStack(spacing: 8, alignment: .center, distribution: .fill) private lazy var vStack = VStack(spacing: 4, alignment: .fill, distribution: .fill) private lazy var titleHStack = HStack(spacing: 4, alignment: .center, distribution: .fill)

private var isFollow: Bool = false { didSet { self.follow.isHidden = isFollow self.followLabel.isHidden = !isFollow } } ```

```swift addSubview(hStack) hStack.snp.makeConstraints { make in make.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)) }

iconView.sizeConstraint = CGSize(width: 50, height: 50) follow.sizeConstraint = CGSize(width: 60, height: 30) hStack.addArrangedSubviewsMakeConstraint([iconView, vStack, hStack.spacer(), follow]) vStack.addArrangedSubviews([titleHStack, detail])

followLabel.sizeConstraint = CGSize(width: 50, height: 15) titleHStack.addArrangedSubviewsMakeConstraint([title, followLabel, titleHStack.spacer()]) ```

滚动布局

StackView有时候也可以使用配合ScrollView一起使用,效果如同TableView,但是这个则需要使用好ScrollView的contentSize,使用frame布局,则需要手动设置;使用自动布局,则需要ScrollView中的contentView来填充,最终ScrollView的contentSize取决于contentView。

Simulator Screen Recording - iPhone 14 Pro - 2022-09-18 at 23.22.56.gif

有时候,写个简单的页面,真的不需要那么多代理,这不是更简单吗?

```swift view.addSubview(scrollView) scrollView.snp.makeConstraints { make in make.edges.equalTo(view.safeAreaLayoutGuide) }

scrollView.addSubview(vStack) vStack.snp.makeConstraints { make in make.edges.equalToSuperview(); make.width.equalToSuperview() } ```

结尾

文章使用了几个简单的实例,一点点的演变了不同的布局方式,在我们日常开发中,或许有那些简单极致的页面,或许也有那些花里胡哨的页面,不管如何,布局的思路都不会变,其实从实例中可以看出,布局代码所占篇幅并不多,在配合使用一些扩展类,其实使用StackView纯代码布局是不是比想象中要香很多呢。