第四章 Preview Device|Expand|Alignment|LineLimit|Rectangle|ForegroundColor

0 阅读4分钟

我们接下来进行将登陆界面中间的部分抽离成组件。

我们新建一个 SwiftUIViewLoginValueContentView.swift , 放在和 LoginPage.swift 同级新建的文件夹 View中。

image-20211116140429108

Preview Device

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

image-20211116140701851

我们将预览设备修改为 SizeThatFits

image-20211116140823647

这样在看我们的控件预览,只有我们需要的那么多了。

为了能够很好的封装我们的组件,我们先按照选择服务器的组件进行封装。我们将服务器图标和选择下拉的图标资源拖到工程里面。

var body: some View {
    Image("server_icon")
    Image("drop_icon")
}
image-20211116141350919

使用 HStack 横向布局

但是这两个图标竟然直接分别显示了,竟然在显示整个设备不一样,出乎我们的意料。既然这两个图标分别是在组件的左侧和右侧,那么我们就用 HStack 进行包裹。

HStack {
    Image("server_icon")
    Image("drop_icon")
}
image-20211116141618464

但是这挨的也太紧密了吧,我们在中间添加一个 Spacer 试一下。

var body: some View {
    HStack {
        Image("server_icon")
        Spacer()
        Image("drop_icon")
    }
}
image-20211116141810798

果然一下子组件的大致的模样就出来了,我们只需要在中间添加一个 Text,岂不是就万事大吉了。

HStack {
    Image("server_icon")
    Text("请选择服务器")
    Image("drop_icon")
}

image-20211116142058626

通过 .frame(maxWidth: .infinity) 实现 Expand

我们需要我们中间的 Text 充满中间剩余的区域,那么就需要 Expand View。但是在 SwiftUI 没有 FlutterExpand 的组件。

但是我竟然找到了和和 Flutter 类似的东西, 设置最大宽度为最大。

var body: some View {
    HStack {
        Image("server_icon")
        Text("请选择服务器")
            .frame(maxWidth:.infinity)
        Image("drop_icon")
    }
}

image-20211116142407678

通过 .frame(alignment:) 设置布局

可是我们想要是文本从左侧显示,我们刚才 .frame() 的操作符号里面竟然有 alignment 参数,我们将 alignment = .leading

var body: some View {
    HStack {
        Image("server_icon")
        Text("请选择服务器")
            .frame(maxWidth:.infinity,
                   alignment: .leading)
        Image("drop_icon")
    }
}

image-20211116142835775

这样看来我们组件似乎十分的完美,一般我们服务器的域名都是十分的长,我们设置一个非常长的文本试一下。

var body: some View {
    HStack() {
        Image("server_icon")
        Text("请选择服务器请选择服务器请选择服务器请选择服务器")
            .frame(maxWidth:.infinity,
                   alignment: .leading)
        Image("drop_icon")
    }
}

image-20211116143251743

使用 .lineLimit() 限制 Text 行数

超长的文本自动换了行,如果换了行,这个组件看起来和下面的输入用户名和密码不是很协调,那么设置文本的最大显示行数为一行。

var body: some View {
    HStack() {
        Image("server_icon")
        Text("请选择服务器请选择服务器请选择服务器请选择服务器")
            .frame(maxWidth:.infinity,
                   alignment: .leading)
            .lineLimit(1)
        Image("drop_icon")
    }
}

image-20211116143544559

通过 spacing 设置 VStack|HStack 设置间隙

此时我们组件的预览效果感觉比设计图的更紧凑一些,我们修改 HStack 默认的间隙。

var body: some View {
    HStack(spacing: 15) {
        Image("server_icon")
        Text("请选择服务器请选择服务器请选择服务器请选择服务器")
            .frame(maxWidth:.infinity,
                   alignment: .leading)
            .lineLimit(1)
        Image("drop_icon")
    }
}

image-20211116143802540

使用 Rectangle 实现分割线

我们组件最下方还有一个同等长度的线条,用户让组件看起来更加的鲜明。我们在最外层添加一个 VStack

对于一条线,确实没有对应的组件,我们只找到了替代的组件 Rectangle

后续我们发现了可以使用 Divider实现分割线

var body: some View {
    VStack {
        HStack(spacing: 15) {
            Image("server_icon")
            Text("请选择服务器请选择服务器请选择服务器请选择服务器")
                .frame(maxWidth:.infinity,
                       alignment: .leading)
                .lineLimit(1)
            Image("drop_icon")
        }
        Rectangle()
    }
}
image-20211116144835048

但是我们底部被新增的 Rectangle 充满了,看了 Rectangle 组件和 Spacer 一样的作用,只不过 Rectangle 是可见的。

我们修改一下 Rectangle 组件的高度为 0.5,这样看起来更像一条线。为了可以清楚的看到,我们运行预览

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)
    }
}

image-20211116145146294

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

image-20211116145933529

使用 .foregroundColor 调整线颜色

我们希望我们底部的线颜色更淡一些。

Rectangle()
    .frame(height:0.5)
    .foregroundColor(Color(red: 0.8, green: 0.8, blue: 0.8))

image-20211116150742921

我们将显示服务器地址的 Text 也设置为当前的颜色。

我们此时想一下,既然线的颜色和显示服务器地址的文本颜色一致,那么我们可以封装一下,我们在 Define 目录新建一个 AppColor

class AppColor: ObservableObject {
}

我们为什么要用实现 ObservableObject 协议呢,因为既然颜色作为 App 的配色,一定有自己规范,当自己整个主色被修改,那么整个 App 的颜色就要马上发生改变。

为了我们可以将十六进制颜色 FFCCCCCC转换为 UIColor,我们需要引入一个第三方库。

github.com/yeahdongcn/…