文章摘要
GPT 4
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结

说在前面

每种语言都有类似的属性,就是为了 一次定义,多处复用 的思想,减少代码的冗余。

自定义视图组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import SwiftUI

struct YikunText: View{
var text: String
var body: some View {
Text(text)
.foregroundColor(.white)
.padding()
.background(.blue)
}
}

struct ContentView: View {
var body: some View {
VStack{
YikunText(text: "易困Yikun")
YikunText(text: "无限进步")
}
}
}

自定义视图组件demo

这里我们封装了一个结构体 YikunText ,然后就可以直接使用这个封装好的组件,与ContentView的区别不大,都遵循了 View 协议,目的是为了将视图的样式和布局代码进行封装,提高代码的复用性,在前端代码里很常见,比如三框架中就叫做组件 components

ViewModifier 视图修改器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import SwiftUI

struct YikunText: ViewModifier{
func body(content: Content) -> some View {
content
.foregroundColor(.white)
.padding()
.background(.blue)
}
}

struct ContentView: View {
var body: some View {
VStack{
Text("易困Yikun")
.modifier(YikunText())
Text("无限进步")
.modifier(YikunText())
}
}
}

这次我们使用 ViewModifier 实现了相同的效果,它们的目的相同,都是为了方便地修改和定制视图。

定义方式不同:

  • 自定义视图(如YikunText):通过定义一个遵循View协议的结构体来创建自定义视图。这个结构体有一个body计算属性,用于返回视图内容。在body中可以直接组合和定制多个视图,并设置它们的样式。
  • ViewModifier:通过定义一个遵循ViewModifier协议的结构体来创建。这个结构体需要实现一个 body(content: Content) -> some View 方法,其中 content 是要被修改的视图,方法返回修改后的视图。

应用方式不同:

  • 自定义视图(如YikunText):通过创建自定义视图结构体的实例来使用。在其他视图中,可以像使用普通视图一样使用自定义视图,如在ContentView中使用 YikunText(text: “易困Yikun”)
  • ViewModifier:通过视图的.modifier()方法来应用,如 Text(“易困Yikun”).modifier(YikunText())

结合扩展extension来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import SwiftUI

struct YikunText: ViewModifier{
func body(content: Content) -> some View {
content
.foregroundColor(.white)
.padding()
.background(.blue)
}
}

extension View{
func titleStyle() -> some View{
modifier(YikunText())
}
}

struct ContentView: View {
var body: some View {
VStack{
Text("易困Yikun")
.titleStyle()
Text("无限进步")
.titleStyle()
}
}
}

这种写法同样能实现上面的效果,它是利用 ViewModifier 来创建可复用的视图样式修改逻辑,并通过扩展(extension)为 View 类型添加了一个便捷的方法,使得多个视图能够方便地应用该样式。

结合上面实例实现水印效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import SwiftUI

struct YikunText: ViewModifier{
func body(content: Content) -> some View {
content
.foregroundColor(.white)
.padding()
.background(.blue)
}
}

struct Watermark: ViewModifier{
var text: String
func body(content: Content) -> some View {
ZStack(alignment: Alignment.bottomTrailing){
content

Text(text)
.font(.caption)
.foregroundColor(.white)
.padding(5)
.background(.black)
}
}
}

extension View{
func titleStyle() -> some View{
modifier(YikunText())
}
func watermarked(with text: String) -> some View{
modifier(Watermark(text: text))
}
}

struct ContentView: View {
var body: some View {
VStack{
Text("无限进步")
.frame(width: 100,height: 100)
.titleStyle()
.watermarked(with: "易困Yikun")
}
}
}

水印效果

Watermark 结构体部分:

同样遵循 ViewModifier 协议,并且额外接收一个 text 参数。

在 body 方法中,使用 ZStack 进行视图叠加布局,先放置传入的原始 content 视图,然后在右下角(通过 Alignment.bottomTrailing 对齐方式)添加一个文本水印。水印文本具有特定的样式,如设置为小字号(.caption 字体)、白色前景色、添加内边距以及黑色背景,实现了为视图添加自定义文本水印的功能。

高级进阶 网格布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

import SwiftUI

struct GridStack<Content: View>: View{
let rows: Int
let columns: Int
@ViewBuilder let content: (Int, Int) -> Content

var body: some View{
VStack{
ForEach(0..<rows, id:\.self){ row in
HStack{
ForEach(0..<columns,id:\.self){ column in
content(row, column)
}
}
}
}
}
}

struct ContentView: View {
var body: some View {
GridStack(rows: 4, columns: 4){ row, col in
Image(systemName: "\(row*4 + col).circle")
Text("R\(row) C\(col)")
}
}
}

网格布局

知识点

  1. 泛型编程:
    使用泛型来定义 GridStack 结构体,使得它可以处理不同类型的视图作为其内部单元格内容,提高了代码的复用性和通用性。这是一种很重要的编程思想,能够避免为不同的视图类型编写重复的相似代码,只要这些视图遵循 View 协议即可融入到 GridStack 的布局当中。
  2. 视图构建与组合:
    • 通过 VStackHStack 以及 ForEach 循环的配合,展示了如何在 SwiftUI 中动态地构建复杂的视图布局结构。利用 ForEach 可以方便地根据数据(这里是行和列的索引)来重复生成视图元素,然后通过嵌套的布局容器将这些元素组合成想要的布局形式,比如这里构建出了网格布局。
    • @ViewBuilder 属性包装器的运用,让闭包内构建视图变得更加简洁直观,它允许像在普通视图结构体的 body 里那样书写视图代码,使得代码的可读性更好,也符合 SwiftUI 中视图构建的语法习惯。
  3. 尾随闭包语法:
    在 ContentView 中创建 GridStack 实例时使用了尾随闭包语法,将原本应该写在括号内的闭包参数移到了括号外面,使代码更加简洁、易读,尤其是当闭包内容较多、逻辑较复杂时,这种语法能让代码结构更加清晰,是 Swift 语言中一种常用的提高代码可读性的语法特性。。