这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
一、目标
上节重点描述了图片选择组件的实现方式,这节实现剩余的UI绘制。
首先绘制一个右下角的按钮
struct BoilingView: View {
@State private var addBoilingViewPresented: Bool = false
var body: some View {
NavigationView{
NavigationLink(
destination: Text("Destination"), //新增沸点页
isActive: $addBoilingViewPresented,
label: {
ZStack(alignment: .bottomTrailing){
ScrollView{
//沸点列表
}
Button(action: {
addBoilingViewPresented = true
}, label: {
ZStack{
RoundedRectangle(cornerRadius: 50).foregroundColor(.blue).frame(width: 75, height: 75)
Image(systemName: "square.and.pencil").foregroundColor(.white).font(.system(size: 35))
}
}).padding()
}
})
}
}
}
NavigationView
+NavigationLink
的组合实现页面跳转。isActive: $addBoilingViewPresented
,通过按钮控制addBoilingViewPresented
变量实现页面跳转的触发。
二、新增沸点页
创建AddBoilingView.swift
替代destination
。
struct AddBoilingView: View {
var body: some View {
ScrollView{
LazyVStack{
}
}.navigationTitle("发布沸点").navigationBarItems(trailing: Button(action: {}, label: {
Text("发布")
})).navigationBarTitleDisplayMode(.inline)
}
}
navigationTitle
指定标题。navigationBarItems
指定发布按钮。.navigationBarTitleDisplayMode(.inline)
设置标题为常显。
三、多行录入框
struct AddBoilingView: View {
@State private var multipleText: String = ""
@State private var textEditorTapped: Bool = false
var body: some View {
ScrollView{
LazyVStack{
if textEditorTapped{
TextEditor(text: $multipleText).frame(height: 100).padding()
} else {
Text("告诉你个秘密,发布沸点不能少于5个字哦,另外添加合适话题会被更多掘友们看见呦~").frame(height: 100).foregroundColor(.gray).padding().onTapGesture {
textEditorTapped = true
}
}
}
}.navigationTitle("发布沸点").navigationBarItems(trailing: Button(action: {}, label: {
Text("发布")
})).navigationBarTitleDisplayMode(.inline)
}
}
SwiftUI
的提供了多行文本域组件TextEditor
,通过双向绑定text
变量来监听用户输入。- 但是
TextEditor
不支持placeHolder
功能,需要自己手写。如以上代码所示,当点击Text
文本后,会将TextEditor
显示出来,间接的达到效果。
四、图片选择按钮和网格展示图片
let columns: [GridItem] =
Array(repeating: .init(.flexible()), count: 3)
ScrollView {
LazyVGrid(columns: columns) {
ForEach((0...79), id: \.self) {_ in
Button(action: {
}, label: {
ZStack{
Rectangle().foregroundColor(Color(red: 248/255, green: 248/255, blue: 248/255))
Rectangle().strokeBorder(style:StrokeStyle(lineWidth: 2.5, lineCap: .round, lineJoin: .round, miterLimit: 1, dash: [10], dashPhase: 0)).aspectRatio(1, contentMode: .fit)
Image(systemName: "plus").font(.system(size: 50))
}.foregroundColor(.gray).padding(1.5)
})
}
}.font(.largeTitle)
}.padding()
最后结合上一节讲过的内容ImagePicker
,最终代码如下:
- 使用
ScrollView
+LazyVGrid
实现网格。 let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 3)
。flexible
指定网格元素宽高自适应。count
指定网格横向元素数量为3。StrokeStyle
指定边框为间隔线的方式。
let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 3)
ScrollView {
LazyVGrid(columns: columns) {
Button(action: {
imagePickerPresented = true
}, label: {
ZStack{
Rectangle().foregroundColor(Color(red: 248/255, green: 248/255, blue: 248/255))
Rectangle().strokeBorder(style:StrokeStyle(lineWidth: 2.5, lineCap: .round, lineJoin: .round, miterLimit: 1, dash: [10], dashPhase: 0)).aspectRatio(1, contentMode: .fit)
Image(systemName: "plus").font(.system(size: 50))
}.foregroundColor(.gray).padding(1.5)
}).sheet(isPresented: $imagePickerPresented, content: {
ImagePicker(images: $images)
})
ForEach((0..<images.count), id: \.self) {index in
let uiImage = images[index]
Image(uiImage: uiImage).resizable().aspectRatio(1, contentMode: .fit)
}
}.font(.largeTitle)
}.padding()
五、键盘工具栏
添加话题按钮实现在之前的案例中描述过多次,这里暂且不谈,感兴趣的可以看下源码。
唯一需要点考究的地方就是最下方的键盘工具栏。
它有3个特性:
-
- 默认悬浮在最下方,无论屏幕怎么滑动。
-
- 如果触发键盘时间,会悬浮在键盘上方。
-
- 工具栏需要加一个遮挡,如果不加的话,出现跟内容重叠的情况会非常的难堪。
基于以上三点,代码如下:
- 最外层使用
ZStack
层叠布局,默认为向底部排列,这样工具栏就会在最下方。 - 工具栏使用
ZStack
+Rectangle
的组合,实现遮挡的效果。
最后效果如下: