MVVM 实现记录文本

1. MVVM 框架说明:

  Model     - 数据层

  View      - 视图层

  ViewModel - 管理模型的视图

2. 资源文件

  2.1 启动图标:

AppIconhttps://img-blog.csdnimg.cn/8fa1031489f544ef9757b6b3ab0eddbe.png

  2.2 Display Name: Do Stuff

  2.2 颜色图:

    

  2.3 项目结构图: 

3. Model 层实现,ItemModel.swift

import Foundation// 不可变结构
struct ItemModel: Identifiable, Codable{var id: Stringlet title: Stringlet isCompleted: Boolinit(id: String = UUID().uuidString, title: String, isCompleted: Bool) {self.id = idself.title = titleself.isCompleted = isCompleted}// 修改值func updateCompleted() -> ItemModel {return ItemModel(id: id, title: title, isCompleted: !isCompleted)}
}

4. ViewModel 层实现,ListViewModel.swift

import Foundation/*CRUD FUNCTIONSCreateReadUpdateDelete*/class ListViewModel: ObservableObject{@Published var items:[ItemModel] = []{didSet{saveItems()}}let itemsKey: String = "items_list"init() {getItems()}func getItems(){// let newItems = [//    ItemModel(title: "This is the first title", isCompleted: false),//    ItemModel(title: "This is the second", isCompleted: true),//    ItemModel(title: "Third", isCompleted: false)// ]// items.append(contentsOf: newItems)// 获取数据, 解码转换数据guardlet data = UserDefaults.standard.data(forKey: itemsKey),let saveItems = try? JSONDecoder().decode([ItemModel].self, from: data)else{ return }self.items = saveItems}// 移动func moveItem(from: IndexSet, to: Int){items.move(fromOffsets: from, toOffset: to)}// 删除 Itemfunc deleteItem(indexSet: IndexSet){items.remove(atOffsets: indexSet)}// 添加 Itemfunc addItem(title: String) {let newItem = ItemModel(title: title, isCompleted: false)items.append(newItem)}// 更新func updateItem(item: ItemModel){// 判断 id 是否一样
//       if let index = items.firstIndex { existingItem in
//            return existingItem.id == item.id
//       }{
//           // run this code
//       }if let index = items.firstIndex(where: { $0.id == item.id}){items[index] = item.updateCompleted()}}// 保存 Items 模型转换为 JSON 数据,然后对其进行,存储func saveItems(){if let encodedData = try? JSONEncoder().encode(items){UserDefaults.standard.set(encodedData, forKey: itemsKey)}}
}

5. View 层实现

  5.1 添加数据页实现,AddView.swift

struct AddView: View {@Environment(\.presentationMode) var presentationMode@EnvironmentObject var listViewModel: ListViewModel@State var textFieldText: String = ""@State var alertTitle: String = ""@State var showAlert: Bool = falsevar body: some View {// 滚动 ViewScrollView {VStack {TextField("Type something here...", text: $textFieldText).padding(.horizontal).frame(height: 55).background(Color(UIColor.secondarySystemBackground)).cornerRadius(10)Button(action: saveButtonPressed) {Text("Save").foregroundColor(.white).font(.headline).frame(height: 55).frame(maxWidth: .infinity).background(Color.accentColor).cornerRadius(10)}}.padding(13)}.navigationTitle("Add an Item 🖋️").alert(isPresented: $showAlert, content: getAlert)}// 单机保存按钮func saveButtonPressed() {if textIsAppropriate() {listViewModel.addItem(title: textFieldText)presentationMode.wrappedValue.dismiss()}}// 检查文本合法性func textIsAppropriate() -> Bool{if textFieldText.count < 3 {alertTitle = "Your new todo item must be at least 3 characters long!!! 😨😰😱"showAlert.toggle()return false}return true}// 获取提示框func getAlert() -> Alert {return Alert(title: Text(alertTitle))}
}struct AddView_Previews: PreviewProvider {static var previews: some View {NavigationView {AddView()}//.preferredColorScheme(.dark).environmentObject(ListViewModel())}
}

  5.2 无数据页实现,NoItemsView.swift

struct NoItemsView: View {// 添加动画@State var animate: Bool = false// 定义颜色let secondaryAccentColor = Color("SecondaryAccentColor")var body: some View {ScrollView{VStack(spacing: 10){Text("There are no items!").font(.title).fontWeight(.semibold)Text("Are you a productive person? I think you should click the add button and a bunch of items to your todo list!").padding(.bottom, 20)NavigationLink(destination: AddView()) {Text("Add Something 🥳").foregroundColor(.white).font(.headline).frame(height: 55).frame(maxWidth: .infinity).background(animate ? secondaryAccentColor : Color.accentColor).cornerRadius(10)}.padding(.horizontal, animate ? 30 : 50).shadow(color: animate ? secondaryAccentColor.opacity(0.7) : Color.accentColor.opacity(0.7),radius: animate ? 30 : 10,x: 0,y: animate ? 50 : 30).scaleEffect(animate ? 1.1 : 1.0).offset(y: animate ? -7 : 0)}.frame(maxWidth: 400).multilineTextAlignment(.center).padding(40).onAppear(perform: addAnimation)}.frame(maxWidth: .infinity,maxHeight: .infinity)}// 添加动画func addAnimation(){guard !animate else { return }DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {withAnimation(Animation.easeInOut(duration: 2.0).repeatForever()){animate.toggle()}}}
}struct NoItemsView_Previews: PreviewProvider {static var previews: some View {NavigationView {NoItemsView().navigationTitle("Title")}}
}

  5.3 列表行 View 实现,ListRowView.swift

struct ListRowView: View {let item: ItemModel;var body: some View {HStack {Image(systemName: item.isCompleted ? "checkmark.circle":"circle").foregroundColor(item.isCompleted ? .green : .red)Text(item.title)Spacer()}.font(.title2).padding(.vertical, 8)}
}struct ListRowView_Previews: PreviewProvider {static var item1: ItemModel = ItemModel(title: "First Item!", isCompleted: false)static var item2: ItemModel = ItemModel(title: "Second Item!", isCompleted: true)static var previews: some View {Group {ListRowView(item: item1)ListRowView(item: item2)}.previewLayout(.sizeThatFits)}
}

  5.4 列表页实现,ListView.swift

struct ListView: View {//    @State var items:[ItemModel] = [
//       ItemModel(title: "This is the first title", isCompleted: false),
//       ItemModel(title: "This is the second", isCompleted: true),
//       ItemModel(title: "Third", isCompleted: false)
//    ]@EnvironmentObject var listViewModel: ListViewModel;var body: some View {ZStack {if listViewModel.items.isEmpty{// 加载 View 时,添加动画NoItemsView().transition((AnyTransition.opacity.animation(.easeIn)))}else{List {ForEach(listViewModel.items) { item inListRowView(item: item).onTapGesture {withAnimation(.linear){listViewModel.updateItem(item: item)}}}.onDelete(perform: listViewModel.deleteItem).onMove(perform: listViewModel.moveItem)}.listStyle(.plain)}}.navigationTitle("Todo List 📝").navigationBarItems(leading: EditButton(),trailing: NavigationLink("Add", destination: AddView()))}
}struct ListView_Previews: PreviewProvider {static var previews: some View {NavigationView {ListView()}.environmentObject(ListViewModel())}
}

  5.5 在 App 文件中添加 ListView 与 ViewModel,TodoListApp.swift

/*MVVM 框架Model     - 数据层View      - 视图层ViewModel - 管理视图的模型*/@main
struct TodoListApp: App {/// ViewModel@StateObject var listViewModel: ListViewModel = ListViewModel()var body: some Scene {WindowGroup {NavigationView {ListView()}// 适配 iPad 导航栏.navigationViewStyle(StackNavigationViewStyle()).environmentObject(listViewModel)}}
}

6. 效果图

          

          

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/4663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

组合(力扣)dfs + 回溯 + 剪枝 JAVA

给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 示例 2&#xff1a; 输入&#xff1a;n 1, …

spring笔记

Transactional 在方法开始前开启事务 检查异常&#xff08;unchecked exception&#xff09;不回滚 如果想针对检查异常进行事务回滚&#xff0c;可以在Transactional注解里使用 rollbackFor属性明确指定异常。 Transactional(rollbackFor Exception.class)catch的异常不回…

在Linux环境中安装配置Django与PostgreSQL数据库

Django是一款功能强大的Python Web框架&#xff0c;而PostgreSQL是一个开源的高级关系型数据库系统。本文将介绍在Linux环境中如何安装和配置Django与PostgreSQL数据库&#xff0c;帮助您搭建一个完整的开发环境。 第一步&#xff1a;安装Django和PostgreSQL 安装Python环境&a…

鲸鱼优化算法MATLAB代码

论文 Seyedali Mirjalili,Andrew Lewis. The Whale Optimization Algorithm[J]. Advances in Engineering Software,2016,95.func_plot.m % This function draw the benchmark functionsfunction func_plot(func_name)[lb,ub,dim,fobj]Get_Functions_details(func_name);switch…

数据结构(王道)——线性表之静态链表顺序表和链表的比较

一、静态链表 定义&#xff1a; 代码实现&#xff1a; 如何定义一个静态链表 静态链表的基本操作思路&#xff1a; 初始化静态链表&#xff1a; 静态链表的查找、插入、删除 静态链表总结&#xff1a; 二、顺序表和链表的比较 逻辑结构对比&#xff1a; 存储结构对比&#xff…

vue3 引入dataV 报错,使用patch-package记录插件包 node_modeule 修改记录。 vite 版DataV

开发数字大屏功能&#xff0c;引用dataV UI组件库比较好用&#xff0c;目前分为Vue2 和 Vue3 两个版本。 Vue2 --DataV版本 yarn add jiaminghi/data-viewVue3 --DataV版本 yarn add dataview/datav-vue3vite – --DataV版本 //不想动手改的&#xff0c;也可以使用此版本&a…

【Zookeeper】

目录 一、Zookeeper 概述1、Zookeeper 定义2、Zookeeper 工作机制3、Zookeeper 特点4、Zookeeper 数据结构5、Zookeeper 应用场景6、Zookeeper 选举机制 二、部署 Zookeeper 集群1.安装前准备1、关闭防火墙2、安装 JDK3、下载安装包 2.安装 Zookeeper1、修改配置文件2、拷贝配置…

被字节拷打了~基础还是太重要了...

今天分享一篇一位同学去字节面试的实习面经&#xff0c;技术栈是java&#xff0c;投了go后端岗位&#xff0c;主要拷打了 redismysql网络系统java算法&#xff0c;面试问题主要集中在 mysql、redis、网络这三部门&#xff0c;因为面试官是搞 go 的&#xff0c;java 只是随便问了…

【微信机器人开发

现在并没有长期免费的微信群机器人&#xff0c;很多都是前期免费试用&#xff0c;后期进行收费&#xff0c;或者核心功能需要付费使用的。 这时如果需要群机器人帮助我们管理群聊&#xff0c;建议大家使有条件的可以自己开发微信管理系统。了解微信群机器人的朋友都知道&#x…

Mysql数据库之事务

目录 一、事务的概念 二、事务的ACID特点 1.原子性&#xff08;Atomicity&#xff09; 2.一致性&#xff08;Consistency&#xff09; 3.隔离性&#xff08;lsolation&#xff09; 4.持久性&#xff08;Durability) 三、并发访问表的一致性问题和事务的隔离级别 1.并发访…

Windows下 创建 FTP 服务器及相关设置

Windows 创建 FTP 服务器 1. 示例功能说明 FTP 服务器根路径下的目录&#xff1a; C:\USERS\SQQIAN\DESKTOP\FTP └─localuser├─FTP1 # 只有用户名为FTP1可以访问&#xff0c;读写均可│ FTP11.txt│├─FTP2 # 只有用户名为FTP2…

好家伙,9:00面试,9:06就出来了,问的实在是太...

从外包出来&#xff0c;没想到死在另一家厂子 自从加入这家公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到2月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资直降30%&#xff0c;顿时有吃不起饭的赶脚。 好在有个兄弟内推我去…

zabbix-server监控mysql数据库及httpd服务、监控apache、监控ftp

目录 一、监控mysql数据库及httpd服务 1、为server.Zabbix.com添加服务模板 2、server.zabbix.com服务端 操作 3、编辑chk_mysql.sh脚本 4、server.zabbix.com测试 二、监控apache 1、获取键值 2、服务器操作 3、zabbix监控web端导入监控模板 4、server.zabbix.com添加…

前端多行文本省略号

.title {height: 4rem;line-height: 2rem;// 多行文本省略号overflow: hidden;font-size: 1.4rem;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;}

Pycharm远程服务器上运行程序报错:Can‘t get remote credentials for deployment server

一、问题描述&#xff1a; 二、解决方法&#xff1a; 1.依次选择 文件 -> 设置 -> 项目 -> Python 解释器,出现如下界面&#xff1a; 2. 点击python 解释器右侧的小齿轮&#xff0c;选择全部显示&#xff1a; 3. 在弹出的窗口中发现存在多个连接到同一个服务器的解释…

【protobuf】socket.io序列化和反序列化

1.背景 后台利用socket.io发送websocket消息&#xff0c;加密用到protobuf 2.反序列化时遇到问题 Traceback (most recent call last): File "D:/locust/Nigeria/test3.py", line 40, in <module> play.ParseFromString(decode_spin_str) google.proto…

FreeSWITCH的强插强拆等

记录如下&#xff1a; 强插强拆都是调用intercept这个appeavesdrop 监听appthree_way 三通app 强插强拆只是主体不同&#xff0c;尝试这样描述&#xff1a; 站在1001的立场上看&#xff0c;1002 bridge 1003&#xff0c; 1001呼入&#xff0c;执行intercept 1003-uuid&#…

chrome edge svg转png

chrome edge svg转png 生成SVG blockdiag Live Preview 导出png 截图&#xff1a; 左上角截取屏幕截图

sessionsManager io.undertow.server.session.InMemorySessionManager

sessionsManager io.undertow.server.session.InMemorySessionManager 记录一次性能优化记录基本情况错误表现错误提示问题原因解决办法 记录一次性能优化记录 基本情况 k8s集群&#xff0c;2台应用&#xff0c;nacos负载均衡&#xff0c;4只交易&#xff0c;2列表&#xff0…

【基于 GitLab 的 CI/CD 实践】02、gitlab-runner 实践

目录 一、gitlab-runner 简介 1.1 要求 1.2 特点 二、GitLab Runner 安装 2.1 使用 GItLab 官方仓库安装 2.2 使用 deb/rpm 软件包 2.3 在容器中运行 GitLab Runner 三、GitLab Runner 注册 3.1 GitLabRunner 类型 3.2 获取 runner token 获取 shared 类型 runner t…