我们接下来进行将登陆界面中间的部分抽离成组件。
我们新建一个 SwiftUI 的 View,LoginValueContentView.swift , 放在和 LoginPage.swift 同级新建的文件夹 View中。

Preview Device
但是我们创建完毕,我们右侧预览的是整个设备,但是对于我们只是封装为一个组件,自然不符合我们需求。

我们将预览设备修改为 SizeThatFits

这样在看我们的控件预览,只有我们需要的那么多了。
为了能够很好的封装我们的组件,我们先按照选择服务器的组件进行封装。我们将服务器图标和选择下拉的图标资源拖到工程里面。
swift
var body: some View {
Image("server_icon")
Image("drop_icon")
}

使用 HStack 横向布局
但是这两个图标竟然直接分别显示了,竟然在显示整个设备不一样,出乎我们的意料。既然这两个图标分别是在组件的左侧和右侧,那么我们就用 HStack 进行包裹。
swift
HStack {
Image("server_icon")
Image("drop_icon")
}

但是这挨的也太紧密了吧,我们在中间添加一个 Spacer 试一下。
swift
var body: some View {
HStack {
Image("server_icon")
Spacer()
Image("drop_icon")
}
}

果然一下子组件的大致的模样就出来了,我们只需要在中间添加一个 Text,岂不是就万事大吉了。
swift
HStack {
Image("server_icon")
Text("请选择服务器")
Image("drop_icon")
}

通过 .frame(maxWidth: .infinity) 实现 Expand
我们需要我们中间的 Text 充满中间剩余的区域,那么就需要 Expand View。但是在 SwiftUI 没有 Flutter 中 Expand 的组件。
但是我竟然找到了和和 Flutter 类似的东西, 设置最大宽度为最大。
swift
var body: some View {
HStack {
Image("server_icon")
Text("请选择服务器")
.frame(maxWidth:.infinity)
Image("drop_icon")
}
}

通过 .frame(alignment:) 设置布局
可是我们想要是文本从左侧显示,我们刚才 .frame() 的操作符号里面竟然有 alignment 参数,我们将 alignment = .leading
swift
var body: some View {
HStack {
Image("server_icon")
Text("请选择服务器")
.frame(maxWidth:.infinity,
alignment: .leading)
Image("drop_icon")
}
}

这样看来我们组件似乎十分的完美,一般我们服务器的域名都是十分的长,我们设置一个非常长的文本试一下。
swift
var body: some View {
HStack() {
Image("server_icon")
Text("请选择服务器请选择服务器请选择服务器请选择服务器")
.frame(maxWidth:.infinity,
alignment: .leading)
Image("drop_icon")
}
}

使用 .lineLimit() 限制 Text 行数
超长的文本自动换了行,如果换了行,这个组件看起来和下面的输入用户名和密码不是很协调,那么设置文本的最大显示行数为一行。
swift
var body: some View {
HStack() {
Image("server_icon")
Text("请选择服务器请选择服务器请选择服务器请选择服务器")
.frame(maxWidth:.infinity,
alignment: .leading)
.lineLimit(1)
Image("drop_icon")
}
}

通过 spacing 设置 VStack|HStack 设置间隙
此时我们组件的预览效果感觉比设计图的更紧凑一些,我们修改 HStack 默认的间隙。
swift
var body: some View {
HStack(spacing: 15) {
Image("server_icon")
Text("请选择服务器请选择服务器请选择服务器请选择服务器")
.frame(maxWidth:.infinity,
alignment: .leading)
.lineLimit(1)
Image("drop_icon")
}
}

使用 Rectangle 实现分割线
我们组件最下方还有一个同等长度的线条,用户让组件看起来更加的鲜明。我们在最外层添加一个 VStack。
对于一条线,确实没有对应的组件,我们只找到了替代的组件 Rectangle。
后续我们发现了可以使用
Divider实现分割线
swift
var body: some View {
VStack {
HStack(spacing: 15) {
Image("server_icon")
Text("请选择服务器请选择服务器请选择服务器请选择服务器")
.frame(maxWidth:.infinity,
alignment: .leading)
.lineLimit(1)
Image("drop_icon")
}
Rectangle()
}
}

但是我们底部被新增的 Rectangle 充满了,看了 Rectangle 组件和 Spacer 一样的作用,只不过 Rectangle 是可见的。
我们修改一下 Rectangle 组件的高度为 0.5,这样看起来更像一条线。为了可以清楚的看到,我们运行预览
swift
var body: some View {
VStack {
HStack(spacing: 15) {
Image("server_icon")
Text("请选择服务器请选择服务器请选择服务器请选择服务器")
.frame(maxWidth:.infinity,
alignment: .leading)
.lineLimit(1)
Image("drop_icon")
}
Rectangle()
.frame(height:0.5)
}
}

我们调整 VStack 的 Spacing , 让看起来底部的线看起来更加紧凑。

使用 .foregroundColor 调整线颜色
我们希望我们底部的线颜色更淡一些。
swift
Rectangle()
.frame(height:0.5)
.foregroundColor(Color(red: 0.8, green: 0.8, blue: 0.8))

我们将显示服务器地址的 Text 也设置为当前的颜色。
我们此时想一下,既然线的颜色和显示服务器地址的文本颜色一致,那么我们可以封装一下,我们在 Define 目录新建一个 AppColor 。
swift
class AppColor: ObservableObject {
}
我们为什么要用实现 ObservableObject 协议呢,因为既然颜色作为 App 的配色,一定有自己规范,当自己整个主色被修改,那么整个 App 的颜色就要马上发生改变。
为了我们可以将十六进制颜色 FFCCCCCC转换为 UIColor,我们需要引入一个第三方库。