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

9,246 阅读4分钟

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

前言

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

即便说过很多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的封装以及添加了便携式的初始化,并不是SwiftUIVStack

/// 布局代码
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

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

Noteswift可以写出比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。

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

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

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纯代码布局是不是比想象中要香很多呢。