接上文:
从零开始的 Swift UI (二)
上篇文章介绍了如何使用 UserDefaults 和 ObserveableObject 来进行数据管理。
这篇文章来完成 LikeView 的布局和功能实现。
Layout
在 LikeView 中编写如下代码。
swift
代码语言:javascript复制1struct LikeView: View {
2 @EnvironmentObject var like: Like
3
4 var likes: [LikeModel] {
5 like.likes
6 }
7
8 var body: some View {
9 ZStack {
10 GeometryReader { _ in
11 List {
12 ForEach(likes) { like in
13 Button(action: {}, label: { Text(like.text) })
14 }
15 }
16 }
17 }
18 }
19}
COPY
再修改 HomeView 中的 Like Button 代码。
swift
代码语言:javascript复制1Button(action: {
2 like.add(hikotoko: model)
3}, label: {
4 Image(systemName: liked ? "suit.heart.fill" : "suit.heart")
5 .foregroundColor(liked ? .red : .primary)
6 .font(.custom("icon", size: 28))
7})
COPY
Like.swift 中新增一个方法。
swift
代码语言:javascript复制1func add(hikotoko: HitokotoModel) -> Bool {
2 let date = ISO8601DateFormatter().date(from: hikotoko.createdAt) ?? Date()
3
4 return add(item: LikeModel(id: UUID(uuidString: hikotoko.uuid) ?? UUID(), text: hikotoko.hitokoto,
5 createdAt: date, from: hikotoko.from, author: hikotoko.creator))
6}
COPY
上面 Like Button 时候被选中,可以根据 Like 中有没有存储判断。
将 ActionView 修改为如下代码:
swift
代码语言:javascript复制1struct ActionView: View {
2 @Binding var model: HitokotoModel?
3 @EnvironmentObject var like: Like
4
5 var liked: Bool {
6 guard let model = model else {
7 return false
8 }
9 return like.has(uuid: UUID(uuidString: model.uuid))
10 }
11
12 @ViewBuilder
13 var body: some View {
14 if let model = model {
15 HStack(spacing: 20) {
16 Button(action: {
17 like.add(hikotoko: model)
18 }, label: {
19 Image(systemName: liked ? "suit.heart.fill" : "suit.heart")
20 .foregroundColor(liked ? .red : .primary)
21 .font(.custom("icon", size: 28))
22 })
23 Button(action: {
24 }, label: {
25 Image(systemName: "square.and.arrow.up")
26 .font(.custom("icon", size: 28))
27 .foregroundColor(.primary)
28 })
29 }
30 }
31 }
32}
COPY
liked
计算属性根据 model 中的 uuid 推断状态。因为使用了 @Binding
所以上层 View 还需要传一个 Binding 给他。可以理解为 React 中的 Props。注意的是 只有加了 @Binding
的参数传递才是引用传递,也就是上层数据更新后下层也会被更新。
在 HomeView 中修改为 ActionView(model: $model).offset(x: 0, y: reader.size.height / 2 - 50)
被 @State
装饰的属性,取他的 Binding 只需要在前面加一个 $
这样点击 Like Button 后 ❤就会变红啦。
Navigation
为了实现能在各个 View 之间导航。使用 NavigationView 就可以做到啦。
修改 HomeView,在外层加上 NavigationView。
修改 LikeView,在外层加上 NavigationView。
swift
代码语言:javascript复制1var body: some View {
2 NavigationView {
3 ZStack {
4 GeometryReader { _ in
5 List {
6 ForEach(likes) { like in
7 Button(action: {}, label: { Text(like.text) })
8 }
9 }
10 }
11 }.navigationBarTitle("喜欢")
12 }
13}
COPY
注意在设定 .navigationBarTitle
必须加在 NavigationView 的子 View 上才会生效。
接下来,调整一下 List 的 style,让 Item 撑满整个宽度。只需要使用内置的 .listStyle(PlainListStyle())
即可。
其余知识点将通过小 Demo 描述。
- Share
- Sheet Modal
完整 App:
https://github.com/Innei/meet-swift
(完)