前言
在前两篇文章讲述了UIStackView布局思想,使用方法以及一些实用的案例,在案例中使用xib结合UIStackView,缺少一些对纯代码的补充,这篇文章,我们主要聊聊如何使用StackView来写纯代码布局。
- 使用UIStackView来简化iOS的界面布局
- UIStackView之一问一答
即便说过很多StackView的好,但是还是很多人认为复杂的页面用不上,其实真正理解了StackView的布局思想,不管是结构层级简单的布局亦或者复杂的布局,也不管是使用Inferface Builder
来构建UI,还是使用纯代码,都能够游刃有余。
下面,我会使用swift演示使用纯代码是怎样布局的。如果有兴趣,点击下载Demo查看效果。下面所展示的代码只是截取的布局部分。
简单布局
简单布局,我归纳为,一行或者一列的元素组成的。通常有类页面如设置页、通讯录。如下布局中,一个hStack包含了image、label、button,组成了一个简单的布局。
结构如下:
HStack: image + label + Button
/// 懒加载
private lazy var vStack = VStack(spacing: 16)
Note: 这里的
VStack
实际上是对UIStackView的封装以及添加了便携式的初始化,并不是SwiftUI
中VStack
。
/// 布局代码
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])
Note:
sizeConstraint、heightConstraint、widthConstraint、addArrangedSubviewsMakeConstraint、spacer()
这些都是自己添加分类方法。
嵌套布局
嵌套布局,我归纳为,界面的元素多样化,需要使用两个以上StackView的布局(不同排列方向)。
结构如下:
HStack:image + VStack + Button
VStack:label + label
/// 懒加载
private lazy var hStack = HStack(spacing: 8, alignment: .center, distribution: .fill)
private lazy var vStack = VStack(spacing: 4, alignment: .fill, distribution: .fill)
Note:
swift
可以写出比OC
更多的语法糖,这是语法的特性所在。从初始化方法上就可以看出。
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重新布局。
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
}
}
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。
有时候,写个简单的页面,真的不需要那么多代理,这不是更简单吗?
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纯代码布局是不是比想象中要香很多呢。