Swift UI 框架 实战 简易计数器、待办清单 、随机壁纸图库、个人笔记

实现一个简易的计数器

Swift 复制代码
import SwiftUI
struct ContentView: View {
    @State private var count = 0
    var body: some View {
        VStack {
            Text("简易计数器 ")
                .font(.largeTitle)
            Text("\(count)")
                .font(.largeTitle)
        }
        Button {
            count += 1
        } label: {
            Text("点我+1")
        }
        .padding()
    }
}
 
#Preview {
    ContentView()
}

没啥可讲的。 注意一下count用@state就行

Swift 复制代码
import SwiftUI
struct ContentView: View {
    var body: some View {
      
        }
        .padding()
    }
}
#Preview {
    ContentView()
}

以上就是代码最初的框架。。 .padding是界内留白用的 那个#preview也是方便看界面的

contentview是个结构体 它要求遵循view协议 view就是整个界面 也就是最重要的

定义一个body元素去描述界面里的东西 some view意思就是这个body返回的是一个view的东西

这个some用的很有意思 很人文(英语大佬应该懂,额我有点懂似乎,但我不是大佬)具体可以看看前面,提到过some view. 嗯就这样

实现一个待办清单Todo

第 1 步:定义待办事项的数据模型

待办事项有 3 个特征:

  1. 唯一 id(列表必须要)
  2. 标题文字
  3. 是否完成

我们新建一个结构体 Todo

Swift 复制代码
// 写在 ContentView 外面
struct Todo: Identifiable {
    let id = UUID()       // 唯一id,列表自动识别
    var title: String     // 待办文字
    var isDone: Bool      // 是否完成
}

第 2 步:在页面里加 待办列表数据源

@State 保存整个待办数组,页面才能刷新

Swift 复制代码
struct ContentView: View {
    // 🔥 核心数据:所有待办都存在这里
    @State private var todoList: [Todo] = []
    // 输入框里的文字
    @State private var inputText = ""

    var body: some View {
        NavigationStack {
            Text("待办清单")
        }
    }
}

第 3 步:搭建页面布局结构

页面分上下两部分:

  • 上面:输入框 + 添加按钮
  • 下面:待办列表

VStack 垂直排列

Swift 复制代码
var body: some View {
    NavigationStack {
        VStack(spacing: 0) {
            // 第一部分:输入框+按钮(后面填内容)
            HStack {

            }
            .padding()

            // 第二部分:待办列表(后面填内容)
            List {

            }
        }
        .navigationTitle("待办清单")
    }
}

现在页面是空框架,结构已经搭好了。


第 4 步:实现上面的「输入框 + 添加按钮」

给 HStack 里补上输入框和按钮

Swift 复制代码
HStack {
    // 输入框:双向绑定inputText
    TextField("输入待办事项", text: $inputText)
        .padding(10)
        .background(Color.gray.opacity(0.2))
        .cornerRadius(8)
    
    // 添加按钮
    Button("添加") {
        // 点击执行:新建待办,加到列表里
        if !inputText.isEmpty {
            let newTodo = Todo(title: inputText, isDone: false)
            todoList.append(newTodo)
            inputText = "" // 清空输入框
        }
    }
    .padding(8)
    .foregroundColor(.white)
    .background(Color.blue)
    .cornerRadius(8)
}

✅ 现在你可以打字、点添加,数据已经能进列表了,只是还没显示出来。

Swift 复制代码
import SwiftUI

struct Todo: Identifiable {
    let id = UUID()       // 唯一id,列表自动识别
    var title: String     //内容
    var isDone: Bool
}
struct ContentView: View {
    private func deleteTodo(at offsets: IndexSet) {
           todoList.remove(atOffsets: offsets)
       }
    @State private var todoList : [Todo] = []
    @State private var inputText = ""
    var body: some View {
        NavigationStack {
            VStack{
                HStack{
                    TextField("输入待办事项", text: $inputText)
                        .padding(10)
                        .background(Color.gray.opacity(0.2))
                        .cornerRadius(8)
                }
                .padding()
                Button("添加") {
                       if !inputText.isEmpty {
                           let newTodo = Todo(title: inputText, isDone: false)
                           todoList.append(newTodo)
                           inputText = ""
                       }
                   }
                .padding(8)
                .foregroundColor(.white)
                .background(Color.blue)
                .cornerRadius(8)
                List {
                    ForEach($todoList) { $todo in//循环遍历
                        HStack {
                            // 勾选圆圈按钮
                            Button {
                                todo.isDone.toggle() // 点击切换完成/未完成
                            } label: {
                                Image(systemName: todo.isDone ? "checkmark.circle.fill" : "circle")
                            }
                            Text(todo.title)
                                .strikethrough(todo.isDone)
                        }
                    }
                    .onDelete(perform: deleteTodo)
                }
                .navigationTitle("备忘录")
                .toolbar {
                    EditButton()
                }
            }
        }
        .padding()
    }
}
 
#Preview {
    ContentView()
}

按我的想法手搓了一遍 感觉还不错

Swift 复制代码
import SwiftUI
struct Todo : Identifiable{
    let id=UUID()
    var isdone:Bool
    var title : String
}

struct ContentView: View {
    private func deletetodo(at offsets : IndexSet){
        todolist.remove(atOffsets: offsets)
    }
    @State private var todolist : [Todo] = []
    @State private var message = ""
    var body: some View {
        NavigationStack{
            Text("备忘录")
                .font(.largeTitle)
                .padding()
            HStack{
                TextField("输入代办事件",text :$message)
                    .padding(10)
                    .background(Color.gray.opacity(0.2))
                    .cornerRadius(8)
                
            }
            .padding()
            List{
                ForEach($todolist){ $todo in
                    HStack{
                        Button{
                            todo.isdone.toggle()
                        } label: {
                            Image(systemName: todo.isdone ? "checkmark.circle.fill" : "circle" )
                        }
                        Text(todo.title)
                    }
                }
                .onDelete(perform: deletetodo)
            }
            .toolbar{
                EditButton()
            }
            Spacer()
            Button("添加"){
                if !message.isEmpty{
                    let newTodo = Todo(isdone : false,title: message)
                    todolist.append(newTodo)
                    message = ""
                }
            }
            .padding(8)
            .foregroundColor(.white)
            .background(Color.blue)
            .cornerRadius(8)
            
        }
        .padding()
    }
}
#Preview {
    ContentView()
}

实现一个随机壁纸图库(调API的)

稍微规范、稍微像样的 App 都会用 Navigation

没有一个上线 App 是只有一个页面、点哪儿都不跳转的。

Navigation = 页面管理器它管这 3 件事:

  • 页面之间跳转
  • 页面顶部标题
  • 页面左上角返回按钮

因为任何真实 App 都一定有:

  • 首页
  • 详情页
  • 设置页
  • 个人中心
  • 列表跳详情

只要有多个页面 → 必须用 NavigationStack

Swift 复制代码
import SwiftUI

// 图片模型(Identifiable 列表专用)
struct RandomImage: Identifiable {
    let id = UUID()
    let imageUrl: URL
}

struct ContentView: View {
    @State private var imageList: [RandomImage] = []
    @State private var tip = "正在加载图片..."

    var body: some View {
        NavigationStack {
            VStack(spacing: 20) {
                Text("🖼️ 随机壁纸图库")
                    .font(.largeTitle.bold())
                
                Text(tip)
                    .foregroundColor(.secondary)
                
                // 图片列表
                List(imageList) { item in
                    AsyncImage(url: item.imageUrl) { phase in
                        switch phase {
                        case .empty:
                            ProgressView()
                                .frame(maxWidth: .infinity, )
                        case .success(let image):
                            image
                                .resizable()
                                .scaledToFill()
                                .frame(maxWidth: .infinity,)
                                .clipped()
                        case .failure:
                            Text("图片加载失败")
                                .frame(maxWidth: .infinity, )
                        @unknown default:
                            EmptyView()
                        }
                    }
                }
                
                // 刷新按钮:重新加载一批随机图
                Button("刷新一批壁纸") {
                    Task {
                        await loadRandomImages()
                    }
                }
                .padding(.horizontal, 40)
                .padding(.vertical, 12)
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(12)
            }
            .padding()
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color(.systemGray6))
            .navigationTitle("随机壁纸")
            .onAppear {
                Task {
                    await loadRandomImages()
                }
            }
        }
    }
    
    // MARK: async/await 并发网络请求(你学的重点!)
    private func loadRandomImages() async {
        tip = "正在请求网络..."
        var list: [RandomImage] = []
        
            // 循环生成6张随机国外壁纸图片链接(100%可访问)
            for _ in 0..<6 {
                let url = URL(string: "https://picsum.photos/800/1200")!
                list.append(RandomImage(imageUrl: url))
            }
            
            // 主线程更新UI @MainActor
            await MainActor.run {
                imageList = list
                tip = "加载成功"
            }
            
        }
    }

#Preview {
    ContentView()
}
  1. 主线程 :负责显示 UI、按钮、图片(不能卡住
  2. 后台线程 :负责网络、耗时操作(不卡界面
  3. async / await / Task
    • Task = 开一个 "后台任务"
    • async = 这个函数放后台跑
    • await = 等它跑完,不卡界面

按运行顺序讲整个 APP 的逻辑


第 1 步:APP 启动 → 显示界面

Swift 复制代码
NavigationStack {
    VStack {
        Text("🖼️ 随机壁纸")
        List(...)
        Button(...)
    }
}

这一步跑在:主线程(UI 线程) 界面瞬间画出来 此时列表是空的,因为 wallpapers 还是空数组 []


第 2 步:界面出现 → 触发 .onAppear

Swift 复制代码
.onAppear {
    Task {
        await loadWallpapers()
    }
}

这里发生了什么?

  1. onAppear 是 "页面显示完了" 的通知
  2. Task { ... }开一个后台任务
  3. 这个任务会去执行:await loadWallpapers()

第 3 步:进入并发函数 loadWallpapers()

Swift 复制代码
private func loadWallpapers() async {
    var list: [Wallpaper] = []
    
    for _ in 0..<6 {
        let url = URL(string: "https://picsum.photos/800/1200")!
        list.append(Wallpaper(imageUrl: url))
    }

    await MainActor.run {
        wallpapers = list
    }
}

重点来了:

这个函数前面写了 async它会自动跑在后台线程!

里面做了啥?

  1. 造一个空数组
  2. 循环 6 次,生成 6 个图片网址
  3. 全部都在后台跑,完全不卡 UI!

第 4 步:最关键一句 → await MainActor.run

Swift 复制代码
await MainActor.run {
    wallpapers = list
}

这句话的意思:

我现在在后台线程,我要回到主线程去更新 UI!

为什么必须回去?

因为:修改 @State 变量 → 必须在主线程否则会崩溃、乱码、不刷新。


第 5 步:回到主线程 → 更新数据

Swift 复制代码
wallpapers = list

数据一变SwiftUI 自动刷新界面列表立刻显示 6 张图片!


第 6 步:你点按钮 → 再次刷新

Swift 复制代码
Button("刷新壁纸") {
    Task {
        await loadWallpapers()
    }
}

onAppear 逻辑一模一样

  1. 点按钮
  2. 开 Task
  3. 进后台跑 loadWallpapers
  4. 造新的图片链接
  5. 回到主线程赋值
  6. UI 刷新

自己搓了一遍

Swift 复制代码
import SwiftUI
struct Wallpaper: Identifiable {
    let id = UUID()
    let imageUrl: URL
}

struct ContentView: View {
    @State private var wallpapers: [Wallpaper] = []
    var body: some View {
        NavigationStack {
            VStack(spacing: 20) {
                Text("🖼️ 随机壁纸")
                    .font(.largeTitle.bold())
                
                List(wallpapers) { wp in
                    AsyncImage(url: wp.imageUrl) { image in
                        image
                            .resizable()
                            .scaledToFill()
                            .frame(height: 250)
                            .clipped()
                    } placeholder: {
                        ProgressView()
                    }
                }
                
                Button("刷新壁纸") {
                    Task {
                        await loadWallpapers()
                    }
                }
                .buttonStyle(.borderedProminent)
            }
            .padding()
            .navigationTitle("壁纸库")
            .onAppear {
                Task {
                    await loadWallpapers()
                }
            }
        }
    }
    private func loadWallpapers() async {
        var list: [Wallpaper] = []
        
        for _ in 0..<6 {
            let url = URL(string: "https://picsum.photos/800/1200")!//调的国外网站
            list.append(Wallpaper(imageUrl: url))
        }
    
        await MainActor.run {
            wallpapers = list
        }
    }
}

#Preview {
    ContentView()
}

实现个人笔记app

Swift 复制代码
import SwiftUI

// 1. 数据模型
struct Note: Identifiable, Codable {
    let id = UUID()
    var title: String
    var content: String
    let createTime: Date
}

// 2. 持久化管理
class NoteStorage: ObservableObject {
    @Published var notes: [Note] = []
    private let saveKey = "SavedNotes"
    
    init() {
        loadNotes()
    }
    
    func loadNotes() {
        if let data = UserDefaults.standard.data(forKey: saveKey) {
            if let decoded = try? JSONDecoder().decode([Note].self, from: data) {
                notes = decoded
                return
            }
        }
        notes = []
    }
    
    func addNote(title: String, content: String) {
        let newNote = Note(title: title, content: content, createTime: Date())
        notes.insert(newNote, at: 0)
        saveNotes()
    }
    
    func deleteNote(at offsets: IndexSet) {
        notes.remove(atOffsets: offsets)
        saveNotes()
    }
    
    private func saveNotes() {
        if let encoded = try? JSONEncoder().encode(notes) {
            UserDefaults.standard.set(encoded, forKey: saveKey)
        }
    }
}

// 3. 主页面
struct ContentView: View {
    @StateObject private var storage = NoteStorage()
    @State private var newTitle = ""
    @State private var newContent = ""
    
    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                // Form 表单
                Form {
                    Section("添加新笔记") {
                        TextField("标题", text: $newTitle)
                        TextEditor(text: $newContent)
                            .frame(height: 120)
                        
                        Button("保存笔记") {
                            if !newTitle.isEmpty {
                                storage.addNote(title: newTitle, content: newContent)
                                newTitle = ""
                                newContent = ""
                            }
                        }
                        .disabled(newTitle.isEmpty)
                    }
                }
                .frame(height: 250)
                
                // 笔记列表
                List {
                    ForEach(storage.notes) { note in
                        NavigationLink {
                            NoteDetailView(note: note)
                        } label: {
                            VStack(alignment: .leading) {
                                Text(note.title)
                                    .font(.headline)
                                Text(note.content)
                                    .font(.caption)
                                    .foregroundColor(.gray)
                                    .lineLimit(1)
                            }
                        }
                    }
                    .onDelete(perform: storage.deleteNote)
                }
            }
            .navigationTitle("个人笔记")
            .toolbar {
                EditButton()
            }
        }
    }
}

// 4. 详情页
struct NoteDetailView: View {
    let note: Note
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 20) {
                Text(note.title)
                    .font(.title.bold())
                Text(note.content)
                    .font(.body)
            }
            .padding()
        }
        .navigationTitle("笔记详情")
    }
}

#Preview {
    ContentView()
}

总目标

做一个能保存内容的笔记 App,有这 3 个核心点:

  1. Form:做添加笔记的表单
  2. TextEditor:写长文
  3. UserDefaults:持久化(重启 App 还在)

第 0 步:先搭页面骨架

先写一个空页面,有标题,有导航。

Swift 复制代码
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationStack {
            VStack {
                Text("个人笔记")
            }
            .navigationTitle("我的笔记")
        }
    }
}

#Preview {
    ContentView()
}

👉 现在你有了一个空的导航页面。


第 1 步:造数据模型

笔记需要有:id、标题、内容、时间。我们让它遵守 Identifiable (方便列表) 和 Codable (方便持久化)。

Swift 复制代码
// 写在 ContentView 外面
struct Note: Identifiable, Codable {
    let id = UUID()
    var title: String
    var content: String
    let createTime: Date
}

👉 这代表一条笔记的数据结构。


第 2 步:造持久化管理(核心!)

这是让笔记 "不掉" 的关键。我们用 UserDefaults。新建一个管理类,它负责增、删、查、存

Swift 复制代码
// 写在 ContentView 外面
class NoteStorage: ObservableObject {
    // 发布笔记数组,数据变了就刷新UI
    @Published var notes: [Note] = []
    let saveKey = "SavedNotes"
    
    init() {
        // 一初始化就加载本地数据
        loadNotes()
    }
    
    // 1. 加载数据
    func loadNotes() {
        if let data = UserDefaults.standard.data(forKey: saveKey) {
            if let decoded = try? JSONDecoder().decode([Note].self, from: data) {
                notes = decoded
                return
            }
        }
        // 如果没数据,就是空数组
        notes = []
    }
    
    // 2. 保存数据
    private func saveNotes() {
        if let encoded = try? JSONEncoder().encode(notes) {
            UserDefaults.standard.set(encoded, forKey: saveKey)
        }
    }
    
    // 3. 添加笔记
    func addNote(title: String, content: String) {
        let newNote = Note(title: title, content: content, createTime: Date())
        notes.insert(newNote, at: 0) // 加到最前面
        saveNotes() // 保存
    }
    
    // 4. 删除笔记
    func deleteNote(at offsets: IndexSet) {
        notes.remove(atOffsets: offsets)
        saveNotes() // 保存
    }
}

👉 到这里,我们有了数据存储的逻辑

第 1 块:创建类 + 声明数组

Swift 复制代码
class NoteStorage: ObservableObject {
    @Published var notes: [Note] = []
    let saveKey = "SavedNotes"
}

意思:

  • ObservableObject:让界面能感知数据变化
  • @Published:一改动就刷新界面
  • notes:存所有笔记
  • saveKey:存本地的 "钥匙"

@State 只能管自己页面里的数据 @Published 是给 "外面的管理类" 用的,让它也能刷新界面!

  1. @State 是啥?
  • 放在 View 里面
  • 自己页面的小变量
  • 比如:开关、输入框、数字、颜色
  • 只能自己用,不能共享给别的地方
Swift 复制代码
struct ContentView: View {
    @State private var name = "" // 只能在这个View里用
}

  1. @Published 是啥?
  • 放在 ObservableObject 类里面 (比如你的 NoteStorage
  • 跨页面共享的数据(笔记、列表、用户信息...)
  • 一变,所有用到它的页面都会自动刷新!
Swift 复制代码
class NoteStorage: ObservableObject {
    @Published var notes: [Note] = [] // 共享数据!
}

  1. 为什么你的笔记项目必须用 @Published

因为:你的笔记数据,不能写在 View 里面

  • 增、删、改、存本地
  • 这些是业务逻辑
  • 不能堆在页面里

所以专门建了一个类 NoteStorage 来管理笔记


第 2 块:一启动就加载本地数据

Swift 复制代码
init() {
    loadNotes()
}

意思:

APP 一打开,就自动读本地笔记

第 3 块:加载函数(读数据)

Swift 复制代码
func loadNotes() {
    if let data = UserDefaults.standard.data(forKey: saveKey) {
        if let decoded = try? JSONDecoder().decode([Note].self, from: data) {
            notes = decoded
            return
        }
    }
    notes = []
}

我先给你整句翻译

尝试把本地取出来的二进制 data,重新还原成笔记数组 [Note]。 如果成功了,就把还原出来的数组赋值给 notes,显示到界面上。


我拆成 5 小块,一块一块讲

  1. JSONDecoder()

JSON 解码器 作用:把Data(二进制) 变回 Swift 对象(Note) 就是:数据 → 笔记

  1. .decode( [Note].self, from: data )

这句是核心:

  • [Note].self = 我要转成 **"笔记数组"**
  • from: data = 从哪个二进制数据转

翻译:把 data 还原成 [Note] 数组

  1. try?
  • try = 尝试执行(可能失败)
  • ? = 失败了不崩溃,返回 nil

翻译:尽量去转,转失败就算了,别崩

  1. if let decoded = ...
  • if let = 成功解包
  • 如果解码成功,就把结果放进 decoded

翻译:如果转换成功了......

  1. notes = decoded

把解析成功的笔记数组,赋值给 UI 要用的数组→ 列表马上显示笔记

Swift 复制代码
// 我试试把存进去的二进制数据,变回笔记数组
if let 还原出来的笔记们 = 尝试? 解码器.解码(目标: [Note], 来源: 数据) {

    // 如果成功了!
    界面显示的笔记数组 = 还原出来的笔记们
}

为什么要写这么复杂?

因为:

  1. 本地存的是 Data(二进制)
  2. 界面要用 [Note](模型数组)
  3. 中间必须 Codable + JSONDecoder 转换

整个流程

  1. 写笔记
  2. JSONEncoder 编码 → Data
  3. UserDefaults 存起来
  4. 重启 App
  5. 取出 Data
  6. JSONDecoder().decode([Note].self, from: data)
  7. 变回 [Note]
  8. 显示在列表

你现在卡的这句代码,我再浓缩成 1 句:

把本地存的二进制,重新变回笔记数组,并安全赋值给界面使用。

意思:

  1. 从本地取数据
  2. 把二进制 → 转回笔记数组
  3. 成功就赋值给界面显示
  4. 失败就显示空数组

第 4 块:保存函数(写数据)

Swift 复制代码
private func saveNotes() {
    if let encoded = try? JSONEncoder().encode(notes) {
        UserDefaults.standard.set(encoded, forKey: saveKey)
    }
}

理解 UserDefaults

**UserDefaults = 手机本地的【简易小仓库】**专门存:设置、笔记、配置、偏好、简单数据特点:

  • 关闭 APP 不丢
  • 重启手机还在
  • 卸载 APP 才消失
  • 超级简单,不用数据库

它就是苹果官方原生、新手必学持久化方案


2. UserDefaults 能存什么?

只能存简单基础类型 :String、Int、Bool、Double、Data、Array、Dictionary👉 不能直接存你自己写的 Note 结构体!!

这就是为什么我们要 Codable

复制代码
你的Note结构体 → Codable转成Data → UserDefaults存Data
读取时:UserDefaults取出Data → Codable转回Note

意思:

  1. 把笔记 → 转成二进制
  2. 存进本地
  3. 退出 APP 还在
  • encoded:转好的二进制 Data
  • forKey:钥匙 / 名字,以后靠这个钥匙取出来

第 5 块:添加笔记 + 删除笔记

Swift 复制代码
func addNote(title: String, content: String) {
    let newNote = Note(title: title, content: content, createTime: Date())
    notes.insert(newNote, at: 0)
    saveNotes()
}

func deleteNote(at offsets: IndexSet) {
    notes.remove(atOffsets: offsets)
    saveNotes()
}

意思:

  • 加笔记 → 存本地
  • 删笔记 → 存本地

第 3 步:在页面里使用持久化

现在,在主页面里,我们需要拿到这个存储对象。

Swift 复制代码
struct ContentView: View {
    // 拿到持久化管理器
    @StateObject private var storage = NoteStorage()
    // 表单输入的临时变量
    @State private var newTitle = ""
    @State private var newContent = ""
    
    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                // 这里后面加 Form
                // 这里后面加 List
            }
            .navigationTitle("个人笔记")
        }
    }
}

👉 现在准备好了输入和存储。


第 4 步:实现 Form 表单(你要的重点)

我们用 Form 来做输入区域。

Swift 复制代码
// 放在 VStack 里
Form {
    Section("添加新笔记") {
        TextField("请输入标题", text: $newTitle)
        
        // 多行文本编辑
        TextEditor(text: $newContent)
            .frame(height: 120) // 设置高度
        
        Button("保存") {
            if !newTitle.isEmpty {
                storage.addNote(title: newTitle, content: newContent)
                // 保存后清空输入框
                newTitle = ""
                newContent = ""
            }
        }
        .disabled(newTitle.isEmpty) // 标题空着不能点
    }
}
.frame(height: 250) // 限制Form高度

👉 现在你有了能输入内容的表单


第 5 步:实现笔记列表

把保存的笔记展示出来。

Swift 复制代码
// 放在 Form 下面
List {
    ForEach(storage.notes) { note in
        NavigationLink {
            // 跳转到详情页
            NoteDetailView(note: note)
        } label: {
            VStack(alignment: .leading) {
                Text(note.title)
                    .font(.headline)
                Text(note.content)
                    .font(.caption)
                    .foregroundColor(.gray)
                    .lineLimit(1)
            }
        }
    }
    .onDelete(perform: storage.deleteNote)
}

👉 现在你有了能展示所有笔记的列表,并且能左滑删除。


第 6 步:实现详情页

点进笔记看完整内容。

Swift 复制代码
struct NoteDetailView: View {
    let note: Note
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 20) {
                Text(note.title)
                    .font(.title.bold())
                Text(note.content)
                    .font(.body)
            }
            .padding()
        }
        .navigationTitle("笔记详情")
    }
}
相关推荐
ai_coder_ai2 小时前
自动化脚本ui编程之flexbox布局
ui·autojs·自动化脚本·冰狐智能辅助·easyclick
ZC跨境爬虫3 小时前
UI前端美化技能提升日志day6:(使用苹果字体+计算样式对比差异)
前端·javascript·css·ui·状态模式
游戏开发爱好者83 小时前
深入理解iOSTime Profiler:提升iOS应用性能的关键工具
android·ios·小程序·https·uni-app·iphone·webview
Ulyanov15 小时前
《PySide6 GUI开发指南:QML核心与实践》 第二篇:QML语法精要——构建声明式UI的基础
java·开发语言·javascript·python·ui·gui·雷达电子对抗系统仿真
ai_coder_ai15 小时前
自动化脚本ui编程之垂直滚动布局(vscroll)
ui·autojs·自动化脚本·冰狐智能辅助·easyclick
久爱物联网18 小时前
【WinForm UI控件系列】BarPlot柱状图控件
ui·ui控件·winformui·csharpui控件·桌面ui控件
for_ever_love__19 小时前
UI学习:多界面传值的正向传值(属性传值)和反向传值(代理传值)
学习·ui·ios·objective-c
开心就好20251 天前
全面介绍iOS开发工具:Xcode、AppCode、CocoaPods、Fastlane和Git
后端·ios
Python私教1 天前
FuturesDesk:配置驱动 UI 的 Electron 金融桌面应用模板
ui·金融·electron