美文网首页
SwiftUI入门 - 8.todo状态切换-数据抽象

SwiftUI入门 - 8.todo状态切换-数据抽象

作者: 思跃喵 | 来源:发表于2022-11-23 11:00 被阅读0次

置顶

菜鸟入门,各位大佬轻喷,如有谬误之处欢迎讨论建议,也欢迎各位道友与我同行

“不积跬步,无以至千里;不积小流,无以成江海”

继续

上文中已经实现了 TODO 页面的基本新增逻辑以及删除功能

本文将实现数据每一个 TODO 项的完成状态切换、创建时间

以及滑动删除功能。

同时完成一个数据的抽象,即将数据处理的部分抽象到一个对象内,页面中只管调用即可。

最终效果如下:


在这里插入图片描述

思考

还是老规矩,既然要抽象一个数据模型出来,那就是一个独立的文件。

一个关于 TODO 的数据模型。

至少有两个 struct ,一个 todoItem 的定义,另一个是 todoList 的定义

这个数据模型中是所有的关于这个 todo lists 的操作

如果所有的操作都集中在这个模型中,那我我们的todo页面中的所有操作即可调用这个数据模型。

实现

我们新增一个 TodoModel.swift,内容如下:

import SwiftUI;

// 这里是定义 todo 项的数据结构,结构体用于定义结构,类用于定义完整数据对象
struct TodoItem:Identifiable,Equatable{
    // 给生成一个唯一的id作为标识,相当于实现了 Identifiable
    let id = UUID();
    // todo项名称
    var name:String ;
    // 是否已经完成,默认为false
    var isFinished:Bool = false;
    // 创建时间
    var createTime:Int = 0;
    // 完成时间
    var finishTime:Int = 0;
    // 用来展示的时间,这里相当于是个 computed
    var createdAt:String {
        // 将时间戳转为时间字符串
        if(createTime == 0) {
            return "";
        }
        let date:Date = Date.init(timeIntervalSince1970: Double(createTime))
        let formatter = DateFormatter.init()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return formatter.string(from: date as Date)
    }
}

// ObservableObject 代表这是一个可以被观察的对象
class TodoLists : ObservableObject {
    // @Published 代表这个变量的任何变化都会被发布到外面使用这个变量的地方,更新视图
    // private(set) 代表这个变量的设置、修改等对外隐藏,但是对外可见
    // [TodoItem] 代表这是一个数组,里面的每一条数据都是 TodoItem 类型的
    @Published private(set) var todoList:[TodoItem];
    
    init(todoList: [TodoItem]) {
        self.todoList = todoList
        // 如果是个空数组,那么先放一个进去
        if(todoList.count == 0 ){
            add(name: "请添加TODO")
        }
    }
    
    // 添加一条 todo项,只要名称即可
    func add(name:String){
        if(name == ""){
            return ;
        }
        var item = TodoItem(name: name);
        item.createTime = Int(Date().timeIntervalSince1970);
        self.todoList.insert(item,at: 0);
    }
    
    // 切换todo项的是否完成状态,如果完成状态为true那更新finishTime
    func toggle(item:TodoItem){
        // 找到这一条的索引 index,$0代表这个方法的第一个参数
        let index = todoList.firstIndex(where: {$0.id == item.id})
        if index != nil {
            // index! 代表我知道这个index一定存在,不用再进行判断了
            todoList[index!].isFinished.toggle()
            // 如果是完成,那么更新已完成时间,否则改为0
            if(todoList[index!].isFinished == true){
                todoList[index!].finishTime = Int(Date().timeIntervalSince1970);
            }else{
                todoList[index!].finishTime = 0;
            }
        }
    }
    
    // 删除todo
    func delete(offsets: IndexSet){
        offsets.forEach { index in
            todoList.remove(at: index)
        }
    }
}

既然我们数据模型已经定义好了,那么自然要修改 TodoView.swift页面中的使用

修改如下:

TodoView.swift

import SwiftUI

struct TodoView: View {
    // 是否已经登陆
    @AppStorage("isLogin") private var isLogin:Bool = false;
    // 已经登陆的用户名
    @AppStorage("userName") private var userName:String = "";
    // 输入框输入的新的TODO
    @State private var newItem:String = "";
    // 使用我们新的数据模型
    @StateObject private var todos = TodoLists(todoList: []);
    
    var body: some View {
        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,可以预见,之后我们自己构造数据类型的时候也需要一个 Identifier
                ForEach(todos.todoList){ item in
                    HStack{
                        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{ IndexSet in
                    todos.delete(offsets: IndexSet)
                }
            }.animation(.default,value:todos.todoList)
        }
    }
}

struct TodoView_Previews: PreviewProvider {
    static var previews: some View {
        TodoView()
    }
}

总结

  1. ObservableObject@Published 是在主动定义一个可观察的对象,虽然可以添加许多操作,但是感觉上反而不如 reactive 方法更简洁
  2. 目前看来,Struct 一般用来定义结构或者视图,Class 才是我们普遍意义上的类。
  3. 数据抽象虽然简化了View,但是感觉比较繁琐,或许我应该考虑直接都放到 Struct View里面去,参考 Vue 的结构进行编排,各有优劣,后头试试
  4. 横滑删除的功能非常好实现,直接在 Foreach 后加上 .onDelete 即可
  5. SwiftUI 中有很多这种加方法调用即可实现视图以及功能的方法,也许可以参考到 Vue 或者其他的前端封装里面
  6. 想实现一个 computed变量,直接 var 一个,然后在底下写方法即可

相关文章

  • SwiftUI入门 - 8.todo状态切换-数据抽象

    置顶 菜鸟入门,各位大佬轻喷,如有谬误之处欢迎讨论建议,也欢迎各位道友与我同行 “不积跬步,无以至千里;不积小流,...

  • SwiftUI简单使用

    SwiftUI入门教程[https://github.com/SimpleBoilerplates/SwiftUI...

  • SwiftUI:用枚举切换视图状态

    您已经了解了如何使用常规Swift条件来呈现一种视图或另一种视图,并且我们查看了以下方式的代码: 条件视图特别有用...

  • 精炼Photoshop

    20170303(快速入门) 1、切换屏幕显示模式:f键(英语输入状态)切换,Tab键切换; 2、标尺工具:图像,...

  • SwiftUI 数据状态和绑定

    摘自《SwiftUI和Combine编程》---《数据状态和绑定》 总结: 根据适用范围和存储状态的复杂度的不同,...

  • python-01基础

    python入门 The Zen of Python 数据模型 在Python中数据被抽象成对象,Python程序...

  • SwiftUI里面轮播图有什么第三方库推荐吗

    建议 《SwiftUI实战之轮播图组件实现自动切换图片(教程含源码)》 推荐 基础文章推荐 《SwiftUI是什么...

  • SwiftUI encountered an issue whe

    在SwiftUI中,使用 NavigationLink 时不注意状态共享的问题,很容就会产生数据错乱的bug,并在...

  • AbstractRoutingDataSource分析

    抽象类AbstractRoutingDataSource,通过扩展这个类实现根据不同的请求切换数据源。 Abstr...

  • 简单命令

    MongoDB Shell入门例子 MongoDB Shell db命令【创建切换数据库】 db是指您当前的数据库...

网友评论

      本文标题:SwiftUI入门 - 8.todo状态切换-数据抽象

      本文链接:https://www.haomeiwen.com/subject/dupoxdtx.html