实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)(3)

简介: 实战编程·使用SwiftUI从0到1完成一款iOS笔记App(五)

实战编程-新建笔记页

标题&内容输入

首先还是需要引用ViewModel,才能使用里面声明好的参数。如下代码所示:

// 引用viewModel
    @EnvironmentObject var viewModel: ViewModel

引用viewModel后,其他声明的参数都可以删掉了。当我们在首页笔记列表点击单条笔记时,会打开新建笔记弹窗,并把内容传递过来,因此我们需要声明模型类参数,如下代码所示:

// 引用viewModel
    @EnvironmentObject var viewModel: ViewModel
    // 声明参数
    @State var noteModel: NoteModel
    // 关闭弹窗
    @Environment(.presentationMode) var presentationMode

image.png

声明好需要的参数后,我们来到标题输入框和内容输入框的部分,这是需要绑定的参数就不是之前声明的参数了。当我们是新建笔记的时候,标题和内容应该是为空,也就是绑定在viewModel声明的titlecontent,而如果是编辑笔记,则我们需要绑定的是来自于点击的单条笔记的内容。如下代码所示:

// MARK: 标题输入框
    func titleView() -> some View {
        TextField("请输入标题", text: viewModel.isAdd ? $viewModel.title : $noteModel.title)
            .padding()
    }
    // MARK: 内容输入框
    func contentView() -> some View {
        ZStack(alignment: .topLeading) {
            TextEditor(text: viewModel.isAdd ? $viewModel.content : $noteModel.content)
                .font(.system(size: 17))
                .padding()
            if viewModel.isAdd ? (viewModel.content.isEmpty) : (noteModel.content.isEmpty) {
                Text("请输入内容")
                    .foregroundColor(Color(UIColor.placeholderText))
                    .padding(20)
            }
        }
    }

image.png

完成按钮

完成按钮这块,回忆下我们前几章学习的内容,它应该包含几块内容:

一是判断条件,当我们标题或者内容输入为空的时候,应该提示输入。

二是点击完成操作的时候,也需要判断当前是新增操作还是编辑操作,如果是新增操作,则插入一条新笔记,如果是编辑操作,则需要更新笔记的内容。

我们修改代码如下所示:

// MARK: 完成按钮
    func saveBtnView() -> some View {
        Button(action: {
            //判断当前是新增还是编辑
            if viewModel.isAdd {
                //判断标题是否为空
                if viewModel.isTextEmpty(text: viewModel.title) {
                    viewModel.showToast = true
                    viewModel.showToastMessage = "请输入标题"
                }
                //判断内容是否为空
                else if viewModel.isTextEmpty(text: viewModel.content) {
                    viewModel.showToast = true
                    viewModel.showToastMessage = "请输入内容"
                }
                //校验通过
                else {
                    // 新增一条笔记
                    self.viewModel.addItem(writeTime: viewModel.getCurrentTime(), title: viewModel.title, content: viewModel.content)
                    //关闭弹窗
                    self.presentationMode.wrappedValue.dismiss()
                }
            } else {
                //判断标题是否为空
                if viewModel.isTextEmpty(text: noteModel.title) {
                    viewModel.showToast = true
                    viewModel.showToastMessage = "标题不能为空"
                }
                //判断内容是否为空
                else if viewModel.isTextEmpty(text: noteModel.content) {
                    viewModel.showToast = true
                    viewModel.showToastMessage = "内容不能为空"
                }
                //校验通过
                else {
                    // 保存一条新笔记
                    self.viewModel.editItem(item: noteModel)
                    //关闭弹窗
                    self.presentationMode.wrappedValue.dismiss()
                }
            }
        }) {
            Text("完成")
                .font(.system(size: 17))
        }
    }

image.png

代码好像很多的样子,其实不然,逻辑很简单。

当点击“完成”按钮时,首先需要isAdd状态判断当前是新增还是删除。

如果是新增,则判断viewModel中的输入的标题title和内容content是否为空,如果为空,则更改showToast打开提示信息,已经更新showToastMessage提示信息的内容。如果不为空时,则调用addItem方法新增一条笔记。

如果点击“完成”按钮时的操作为编辑操作,则和上面一样的判断,只是判断为空的参数变成了来源于noteModel的标题title和内容content,当为空判断通过后,则调用editItem编辑方法更新笔记内容。

最后都是调用presentationMode.wrappedValue.dismiss关闭弹窗,当然直接点击关闭按钮时也可以调用这个方法关闭弹窗。

主视图

最后来到新建笔记的body部分,修改部分就只有标题和toast绑定的参数,如下代码所示:

var body: some View {
        NavigationView {
            VStack {
                Divider()
                titleView()
                Divider()
                contentView()
            }
            .navigationBarTitle(viewModel.isAdd ? "新建笔记" : "编辑笔记", displayMode: .inline)
            .navigationBarItems(leading: closeBtnView(), trailing: saveBtnView())
            .toast(present: $viewModel.showToast, message: $viewModel.showToastMessage)
        }
    }

image.png

由于新建笔记页面使用了ViewModel和声明了noteModel模型类,因此我们如果需要预览该页面,则需要在预览的代码中设置默认值,如下代码所示:

struct NewNoteView_Previews: PreviewProvider {
    static var previews: some View {
        NewNoteView(noteModel: NoteModel(writeTime: "", title: "", content: "")).environmentObject(ViewModel())
    }
}

最后,新建笔记页面修改好后,需要回到ContentView首页,我们打开弹窗的路径还没有配置呢。

在新建笔记时,跳转的页面时NewNoteView,如下代码所示:

// 新增笔记
.sheet(isPresented: $viewModel.showNewNoteView) {
  NewNoteView(noteModel: NoteModel(writeTime: "", title: "", content: ""))
}

在编辑笔记时,跳转的页面也是NewNoteView,如下代码所示:

// 编辑笔记
.sheet(isPresented: $viewModel.showEditNoteView) {
  NewNoteView(noteModel: self.item ?? NoteModel(writeTime: "", title: "", content: ""))
}

项目预览

完成后,运行预览效果如下图所示:

image.png

本章小结

恭喜你,完成了使用SwiftUI从0到1完成一款笔记APP的全部内容!

在整个项目过程中,我们首先学习如何完成一个个单独的视图,再将一块块的代码组合成一个页面,最后再基础页面和交互的基础上使用Model-View-ViewModel的方式进行开发调整,最终完成整个项目。

回顾第一个项目的整个过程,我们会发现我们构建视图的方式都是自上而下构建,而实现交互功能、逻辑是自下而上搭建。这便是专栏开始之初提到的编程逻辑:

自顶向下逐步求精的模块化设计思想、面向对象的方法自底而上进行开发思想。

编程技巧固然重要,但更重要的是思维方式,方法很容易学会,但观念和习惯就没有那么容易改变了。

编程本就是一条没有那么有趣的路,不妨沉下心来,写好每一段代码,写好每一块业务。

看着最终成功运行的项目,感受着心底的喜悦喷涌而出~

接下来,我们将继续实现和完成其他项目,请保持期待吧~

相关文章
|
4天前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
23 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
1月前
|
安全 数据安全/隐私保护 Android开发
【05】2025年1月首发完整版-篇幅较长-苹果app如何上架到app store完整流程·不借助第三方上架工具的情况下无需花钱但需仔细学习-优雅草央千澈详解关于APP签名以及分发-们最关心的一篇来了-IOS上架app
【05】2025年1月首发完整版-篇幅较长-苹果app如何上架到app store完整流程·不借助第三方上架工具的情况下无需花钱但需仔细学习-优雅草央千澈详解关于APP签名以及分发-们最关心的一篇来了-IOS上架app
235 75
|
4天前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
29 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
2月前
|
iOS开发 开发者 MacOS
深入探索iOS开发中的SwiftUI框架
【10月更文挑战第21天】 本文将带领读者深入了解Apple最新推出的SwiftUI框架,这一革命性的用户界面构建工具为iOS开发者提供了一种声明式、高效且直观的方式来创建复杂的用户界面。通过分析SwiftUI的核心概念、主要特性以及在实际项目中的应用示例,我们将展示如何利用SwiftUI简化UI代码,提高开发效率,并保持应用程序的高性能和响应性。无论你是iOS开发的新手还是有经验的开发者,本文都将为你提供宝贵的见解和实用的指导。
145 66
|
2月前
|
存储 监控 API
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
90 11
|
3月前
|
传感器 iOS开发 UED
探索iOS生态系统:从App Store优化到用户体验提升
本文旨在深入探讨iOS生态系统的多个方面,特别是如何通过App Store优化(ASO)和改进用户体验来提升应用的市场表现。不同于常规摘要仅概述文章内容的方式,我们将直接进入主题,首先介绍ASO的重要性及其对开发者的意义;接着分析当前iOS平台上用户行为的变化趋势以及这些变化如何影响应用程序的设计思路;最后提出几点实用建议帮助开发者更好地适应市场环境,增强自身竞争力。
|
存储 安全 测试技术
《iOS取证实战:调查、分析与移动安全》一导读
本书适用于对iPhone和其他iOS设备感兴趣的读者,尤其适合那些对设备中能恢复的存储数据类型感兴趣的读者阅读。
1425 0
|
安全 iOS开发
《iOS取证实战:调查、分析与移动安全》一3.9 参考文献
本节书摘来自华章出版社《iOS取证实战:调查、分析与移动安全》一书中的第3章,第3.9节,作者(美)Andrew Hoog Katie Strzempka,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1081 0
|
存储 安全 iOS开发
《iOS取证实战:调查、分析与移动安全》一3.5 存储器类型
本节书摘来自华章出版社《iOS取证实战:调查、分析与移动安全》一书中的第3章,第3.6节,作者(美)Andrew Hoog Katie Strzempka,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1318 0
|
安全 数据安全/隐私保护 iOS开发
《iOS取证实战:调查、分析与移动安全》一2.6 小结
本节书摘来自华章出版社《iOS取证实战:调查、分析与移动安全》一书中的第2章,第2.6节,作者(美)Andrew Hoog Katie Strzempka,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1137 0

热门文章

最新文章

  • 1
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 2
    MNN-LLM App:在手机上离线运行大模型,阿里巴巴开源基于 MNN-LLM 框架开发的手机 AI 助手应用
  • 3
    【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 4
    原生鸿蒙版小艺APP接入DeepSeek-R1,为HarmonyOS应用开发注入新活力
  • 5
    【Azure App Service】基于Linux创建的App Service是否可以主动升级内置的Nginx版本呢?
  • 6
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 7
    【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
  • 8
    【Azure Function】Function App出现System.IO.FileNotFoundException异常
  • 9
    【Azure Logic App】使用MySQL 新增行触发器遇见错误 :“Unknown column 'created_at' in 'order clause'”
  • 10
    阿里云APP备案流程图以及备案所需材料整理,跟着教程一步步操作
  • 1
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    34
  • 2
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 3
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 4
    【Azure Function】Function App门户上的Test/Run返回错误:Failed to fetch
    31
  • 5
    陪玩APP推送配置:陪玩系统手机锁屏收不到推送?可能是这些原因!解决方案来了!
    34
  • 6
    小游戏源码开发之可跨app软件对接是如何设计和开发的
    33
  • 7
    原生鸿蒙版小艺APP接入DeepSeek-R1,为HarmonyOS应用开发注入新活力
    135
  • 8
    PiliPala:开源项目真香,B站用户狂喜!这个开源APP竟能自定义主题+去广告?PiliPala隐藏功能大揭秘
    60
  • 9
    语音app系统软件源码开发搭建新手启蒙篇
    44
  • 10
    MNN-LLM App:在手机上离线运行大模型,阿里巴巴开源基于 MNN-LLM 框架开发的手机 AI 助手应用
    884