简单APP——ToDoList的二次开发(日期规范化+构建搜索栏)

极简第一版

极简版教学:SwiftUI:从零点五开始的APP开发之路 https://www.bilibili.com/video/BV1Kg4y1i7dd?p=1
原项目代码为自己寒假在跟学时的代码,由于版本不同所以和原视频的代码在通知推送方面有一些出入

运行效果

已实现功能

该APP已经是个完整的独立APP,已实现功能如下:
1、自定义添加、收藏和取消收藏、删除事项,并同时支持单选和多选统一操作
2、在事项结束时间到达时向用户发送通知和提醒,在首次打开APP前询问用户许可发送通知权限

待完善

1、日期格式并没有进行设置和规范化
2、在进行事项按时间排序时,对id进行了修改,在swiftUI中很容易会导致一些奇怪的问题
3、已完成数据的增删改而没有查找功能

二次开发

日期格式

原版的日期格式是这个样子的:

这非常乱码,那么我们只需要在初始化的时候,规范一下日期格式
为了方便使用,我们定义一个Date转为规范模式后的String(因为我们输出的时候时以字符串的方式)的方法:

//日期 -> 字符串
func date2String(_ date:Date, dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> String {
    let formatter = DateFormatter()
    formatter.locale = Locale.init(identifier: "zh_CN")
    formatter.dateFormat = dateFormat
    let date = formatter.string(from: date)
    return date
}

然后在SingleCardView中,更改显示日期部分的代码

    Text(date2String(self.UsrData.ToDoList[index].duedate)) //原代码为:self.UsrDate.ToDoList[index].duedate.description,即仅仅将date转换为string
                            .font(.subheadline)
                            .foregroundColor(Color.gray)

完成后新的效果如下:

id的维护

在第一版中,我们在sort排序后,对id进行了更新和修改。在swiftUI中尽量不要修改元素的id,因为id是区分不同View的方式,所以直接更改id会出现一些问题(尤其是动画方面)
对此进行进一步完善主要涉及到UserData里的sort()和ContentView中的SingleCardView

sort()

对于sort()的修改方式及其简单暴力——直接把id更新删掉即可

//第一版:
func sort() {
        self.ToDoList.sort(by: {(data1, data2) in
            return(data1.duedate.timeIntervalSince1970 < data2.duedate.timeIntervalSince1970)
        })
        
        for i in 0..<self.count {
            self.ToDoList[i].id = i
        }
    }

//第二版:
func sort() {
        self.ToDoList.sort(by: {(data1, data2) in
            return(data1.duedate.timeIntervalSince1970 < data2.duedate.timeIntervalSince1970)
        })
    }

SingleCardView

由于sort方法没有更改id,因此元素的id不再与其在数组ToDoList中的个数(index)相同;因此我们使用一个计算属性index来找到ToDoList中对应的singleToDo是在数组中的哪一个;
我们在SingleCardView中以前的index改为以下代码

    var singleData: SingleToDo
    var index: Int{
        self.UsrData.ToDoList.firstIndex(where: {data in data.id == self.singleData.id})!
    }

并在Content()调用SIngleCardView时将传入的index改为singleData

查找(搜索)功能

与uIKit不同的是,SwiftUI没有内置的搜索栏控制,但是搭建一个并不很难

搜索栏UI

IOS中的标准搜索栏,它实际上由一个文本字段和一个取消按钮组成。
首先,我们声明了两个变量:一个是搜索文本的绑定,另一个是存储搜索字段状态的变量(编辑与否)。并且,只有当用户点击搜索字段时,才会显示取消按钮

import SwiftUI

struct Search: View {
    @Binding var text: String
    @State private var isEditing = false
    
    var body: some View {
        
        HStack {
            TextField("Search...", text: self.$text)
                .padding(7)
                .padding(.horizontal, 25)
                .background(Color(.systemGray6))
                .cornerRadius(8)
                .overlay(                                        //文本字段上覆盖两个系统图像
                    HStack {
                        Image(systemName: "magnifyingglass")
                            .foregroundColor(.gray)
                            .frame(minWidth:0, maxWidth: .infinity, alignment: .leading)
                            .padding(.leading, 8)
                        if isEditing {
                            Button(action: {
                                self.text = ""
                            }) {
                                Image(systemName: "multiply.circle.fill")
                                    .foregroundColor(.gray)
                                    .padding(.trailing, 8)
                            }
                        }
                    }
                )
                .padding(.horizontal, 10)
                .onTapGesture {
                    self.isEditing = true
            }
            
            if isEditing {
                Button(action: {
                    self.isEditing = false
                    self.text = ""
                }) {
                    Text("Cancel")
                }
                .padding(.trailing, 10)
                .transition(.move(edge: .trailing))
                .animation(.default)
            }
        }
    }
}

struct Search_Previews: PreviewProvider {
    static var previews: some View {
        Search(text: .constant(""))
            .padding(.leading)
    }
}

效果如下:

使用搜索栏进行数据过滤

切换到ContentView.swift并将搜索栏添加到列表视图中
在body中添加

  Search(text: self.$searchText)
        .padding(.top, 11.0)

视图如下:

然后在显示的时候再加一个判断当前是否在搜索,如果不在就都显示,如果在搜索就只显示title中包含搜索词的事项卡片

                        
                        if searchText.isEmpty {
                            ForEach (self.UsrData.ToDoList) { item in
                                if item.deleted == false {
                                    if !self.showFavouriteOnly || item.isFavourite {
                                        SingleCardView(singleData : item, editingMode: self.$editingMode, selected: self.$selected)
                                            .environmentObject(self.UsrData)
                                            .padding()
                                            .animation(.spring())
                                            .transition(.slide)
                                    }
                                }
                            }
                        } else {
                            ForEach (self.UsrData.ToDoList) { item in
                                if item.deleted == false {
                                    if item.title.contains(self.searchText) {
                                        SingleCardView(singleData : item, editingMode: self.$editingMode, selected: self.$selected)
                                            .environmentObject(self.UsrData)
                                            .padding()
                                            .animation(.spring())
                                            .transition(.slide)
                                    }
                                }
                            }
                        }

完善后效果

小结

SwiftUI的既有他的方便快捷的方式,也方便开发者面向其他UI最终效果进行一个项目的迁移和设计
与Android开发还是有一定不同,优化和美化也是不断学习完善的过程

原文地址:https://www.cnblogs.com/Eirlys/p/14497623.html