SwiftUI实战-仿写掘金APP(四)

2,654 阅读1分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

一、目标

image.png

上节重点描述了图片选择组件的实现方式,这节实现剩余的UI绘制。

首先绘制一个右下角的按钮

image.png


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)设置标题为常显。

image.png

三、多行录入框

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

image.png

最后结合上一节讲过的内容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()

屏幕录制2021-08-30 17.10.44.gif

五、键盘工具栏

添加话题按钮实现在之前的案例中描述过多次,这里暂且不谈,感兴趣的可以看下源码。

唯一需要点考究的地方就是最下方的键盘工具栏。

它有3个特性:

    1. 默认悬浮在最下方,无论屏幕怎么滑动。
    1. 如果触发键盘时间,会悬浮在键盘上方。
    1. 工具栏需要加一个遮挡,如果不加的话,出现跟内容重叠的情况会非常的难堪。

基于以上三点,代码如下:

image.png

  • 最外层使用ZStack层叠布局,默认为向底部排列,这样工具栏就会在最下方。
  • 工具栏使用ZStack+Rectangle的组合,实现遮挡的效果。

最后效果如下:

image.png

六、源码

gitee