[3] 快速學會 SwiftUI 基礎入門

·

3 min read

0. 完成成品

這一篇要用 SwiftUI 來製作一個簡單的待辦清單。

本篇文章是一個步驟指導,建議可以搭配影片一起學習:

1. 開啟 SwiftUI 專案

用 Xcode 新建一個 SwiftUI 的專案

2. 建立一個列表

List 可用來呈現列表,但內容必須要自己定義,這邊用 ForEach 來產生 10 個 Text 的內容:

struct ContentView: View {
    var body: some View {

        List {
            ForEach(1...10, id: \.self) { item in
                Text("\(item)")
            }
        }
    }
}

List 的外觀,也可以變動:

List {
    ForEach(1...10, id: \.self) { item in
        Text("\(item)")
    }
}
.listStyle(PlainListStyle())

3. 建立 Navigation View

這邊新增 Navigation View,並且在右上角新增一個按鈕

struct ContentView: View {
    var body: some View {

        NavigationView {
            List {
                ForEach(1...100, id:\.self) { item in
                    Text("\(item)")
                }
            }
            .navigationTitle("Title")
            .toolbar(content: {
                ToolbarItem(placement: .navigationBarTrailing, content: {
                    Button("Add", action: {
                    })
                })
            })
        }
    }
}

4. 跳轉第二頁

新增一個 PageView2.swift 檔案:

struct PageView2: View {
    var body: some View {
        Text("Page2")
    }
}

原本的 Button 修改為使用 NavigationLink:

NavigationView {
    List {
        ForEach(1...100, id:\.self) { item in
            Text("\(item)")
        }
    }
    .navigationTitle("Title")
    .toolbar(content: {
        ToolbarItem(placement: .navigationBarTrailing, content: {
            NavigationLink("Add", destination: {
                PageView2()
            })
        })
    })
}

5. 第二頁的內容

在第二頁的內容,將會以可以編輯個人的基本資料為主:

struct PageView2: View {

    @State var text = ""

    var body: some View {

        VStack {
            Form {
                TextField("To do...", text: $text)
            }

            Button("Add", action: {
            })
        }
    }
}

6. 建立資料庫

新增一個 Data Model 檔案,並且在此檔案內新增一個名為 Todo 的 ENTITIES,裡面包含了一個欄位:text,型別為 String

截圖 2022-07-08 下午8.13.23.png

7. 讀取資料庫

新增一個 Persistence.swift 檔案,用這段程式碼來去開啟 Model:

import CoreData

struct Persistence {

    static let share = Persistence()

    let container: NSPersistentContainer

    init() {
        container = NSPersistentContainer(name: "Model")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as? NSError {
                print(error)
            }
        })
    }
}

8. 修改主程式

在 App 一開始啟動時,就直接開啟資料庫,並且使用 Environment 傳入,修改如下:

@main
struct TestSwiftUIApp: App {

    let persistence = Persistence.share

    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, persistence.container.viewContext)
        }
    }
}

9. 將資料寫入到資料庫

在第二頁的內容當中,要將 TextField 所輸入的資料寫入到資料庫中,修改如下:

struct SwiftUIView: View {

    @Environment(\.managedObjectContext) var viewContext
    @State var text = ""

    var body: some View {

        VStack {
            Form {
                TextField("To do...", text: $text)
            }

            Button("Add", action: {
                let todo = Todo(context: self.viewContext)
                todo.text = self.text

                do {
                    try self.viewContext.save()
                } catch {
                    let error = error as? Error
                }
            })
        }
    }
}

10. 回到上一頁

按下按鈕後,除了儲存資料外,也要自動跳轉回到上一頁

@Environment(\.presentationMode) var presentationMode
self.presentationMode.wrappedValue.dismiss()

完整程式碼修改如下:

struct SwiftUIView: View {

    @Environment(\.presentationMode) var presentationMode
    @Environment(\.managedObjectContext) var viewContext

    @State var text = ""

    var body: some View {

        VStack {
            Form {
                TextField("To do...", text: $text)
            }

            Button("Add", action: {
                let todo = Todo(context: self.viewContext)
                todo.text = self.text

                do {
                    try self.viewContext.save()
                } catch {
                    let error = error as? Error
                }

                self.presentationMode.wrappedValue.dismiss()
            })
        }
    }
}

11. 讀取資料庫

在第一頁中,使用 FetchRequest 方式將資料讀取出來:

struct ContentView: View {

    @FetchRequest(entity: Todo.entity(), sortDescriptors: [])
    var todos: FetchedResults<Todo>

    var body: some View {

        NavigationView {
            List {
                ForEach(todos) { item in
                    Text(item.text ?? "")
                }
            }
            .navigationTitle("To Do Lists")
            .toolbar(content: {
                ToolbarItem(placement: .navigationBarTrailing, content: {
                    NavigationLink("Add", destination: {
                        PageView2()
                    })
                })
            })
        }

    }
}

12. 左滑刪除

在 List 之中,可以新增左滑刪除的功能:

List {
    ForEach(todos) { item in
        Text(item.text ?? "")
    }
    .onDelete(perform: delete)
}

所以這邊就必須要新增 delete 的函式:

func delete(offsets: IndexSet) {
    if let index = offsets.first {
        let todo = todos[index]
        viewContext.delete(todo)

        do {
            try self.viewContext.save()
        } catch {
            let error = error as? Error
        }
    }
}