干货swift实现todo状态切换
置顶
菜鸟入门,各位大佬轻喷,如有谬误之处欢迎讨论建议,也欢迎各位道友与我同行
不积跬步,无以至千里;不积小流,无以成江海
继续
上文中已经实现了TODO页面的基本新增逻辑以及删除功能
本文将实现数据每一个TODO项的完成状态切换、创建时间
以及滑动删除功能。
同时完成一个数据的抽象,即将数据处理的部分抽象到一个对象内,页面中只管调用即可。
最终效果如下:
思考
还是老规矩,既然要抽象一个数据模型出来,那就是一个独立的文件。
一个关于TODO的数据模型。
至少有两个struct,一个todoItem的定义,另一个是todoList的定义
这个数据模型中是所有的关于这个todolists的操作
如果所有的操作都集中在这个模型中,那我我们的todo页面中的所有操作即可调用这个数据模型。实现
我们新增一个TodoModel。swift,内容如下:importSwiftUI;这里是定义todo项的数据结构,结构体用于定义结构,类用于定义完整数据对象structTodoItem:Identifiable,Equatable{给生成一个唯一的id作为标识,相当于实现了IdentifiableletidUUID();todo项名称varname:String;是否已经完成,默认为falsevarisFinished:Boolfalse;创建时间varcreateTime:Int0;完成时间varfinishTime:Int0;用来展示的时间,这里相当于是个computedvarcreatedAt:String{将时间戳转为时间字符串if(createTime0){return;}letdate:DateDate。init(timeIntervalSince1970:Double(createTime))letformatterDateFormatter。init()formatter。dateFormatyyyyMMddHH:mm:ssreturnformatter。string(from:dateasDate)}}ObservableObject代表这是一个可以被观察的对象classTodoLists:ObservableObject{Published代表这个变量的任何变化都会被发布到外面使用这个变量的地方,更新视图private(set)代表这个变量的设置、修改等对外隐藏,但是对外可见〔TodoItem〕代表这是一个数组,里面的每一条数据都是TodoItem类型的Publishedprivate(set)vartodoList:〔TodoItem〕;init(todoList:〔TodoItem〕){self。todoListtodoList如果是个空数组,那么先放一个进去if(todoList。count0){add(name:请添加TODO)}}添加一条todo项,只要名称即可funcadd(name:String){if(name){return;}varitemTodoItem(name:name);item。createTimeInt(Date()。timeIntervalSince1970);self。todoList。insert(item,at:0);}切换todo项的是否完成状态,如果完成状态为true那更新finishTimefunctoggle(item:TodoItem){找到这一条的索引index,0代表这个方法的第一个参数letindextodoList。firstIndex(where:{0。iditem。id})ifindex!nil{index!代表我知道这个index一定存在,不用再进行判断了todoList〔index!〕。isFinished。toggle()如果是完成,那么更新已完成时间,否则改为0if(todoList〔index!〕。isFinishedtrue){todoList〔index!〕。finishTimeInt(Date()。timeIntervalSince1970);}else{todoList〔index!〕。finishTime0;}}}删除todofuncdelete(offsets:IndexSet){offsets。forEach{indexintodoList。remove(at:index)}}}
既然我们数据模型已经定义好了,那么自然要修改TodoView。swift页面中的使用
修改如下:
TodoView。swiftimportSwiftUIstructTodoView:View{是否已经登陆AppStorage(isLogin)privatevarisLogin:Boolfalse;已经登陆的用户名AppStorage(userName)privatevaruserName:String;输入框输入的新的TODOStateprivatevarnewItem:String;使用我们新的数据模型StateObjectprivatevartodosTodoLists(todoList:〔〕);varbody:someView{VStack{HStack{TextField(请输入新的TODO,text:newItem)。onSubmit{todos。add(name:newItem)newItem}Button(确认){todos。add(name:newItem)newItem}}。padding()List{Foreach开始循环TodoLists的indices,需要它的索引值,用于删除等id需要为一个Identifier,可以预见,之后我们自己构造数据类型的时候也需要一个IdentifierForEach(todos。todoList){iteminHStack{VStack{HStack{字符串拼接,之前已有使用Text((item。name))Spacer()}HStack{Text((item。createdAt))。font(。subheadline)Spacer()}}。foregroundColor(item。isFinished?。gray:。primary)这里用个Group套起来,里面用三元实现点击切换图标,展示是否已经完成Group{item。isFinished?Image(systemName:circle。fill):Image(systemName:circle)}}。contentShape(Rectangle())。onTapGesture{todos。toggle(item:item)}这个调用将实现横滑删除功能}。onDelete{IndexSetintodos。delete(offsets:IndexSet)}}。animation(。default,value:todos。todoList)}}}structTodoViewPreviews:PreviewProvider{staticvarpreviews:someView{TodoView()}}总结1。ObservableObject与Published是在主动定义一个可观察的对象,虽然可以添加许多操作,但是感觉上反而不如reactive方法更简洁2。目前看来,Struct一般用来定义结构或者视图,Class才是我们普遍意义上的类。3。数据抽象虽然简化了View,但是感觉比较繁琐,或许我应该考虑直接都放到StructView里面去,参考Vue的结构进行编排,各有优劣,后头试试4。横滑删除的功能非常好实现,直接在Foreach后加上。onDelete即可5。SwiftUI中有很多这种加方法调用即可实现视图以及功能的方法,也许可以参考到Vue或者其他的前端封装里面6。想实现一个computed变量,直接var一个,然后在底下写方法即可