知识点:
List组件的基本使用、滑动删除
Sheet组件的基本使用
配合@ObservedObject监听数据变化
Userdefault数据缓存
效果
代码
model代码 UserModel.swift
注意点:
1、UserModel遵循了两个协议:
- Identifiable(通过ForEach循环数据时需要标注id来区分数据的唯一性,在模型层可以通过Identifiable并添加id属性,这样在ForEach时就不必在需要手动添加id区分参数)
- Codable(使用userdefault存储复杂数据时需要将数据进行json编解码,因此模型层必须遵循Codable协议)
2、存储数据时可以通过复写didSet方法,这样在控制器层直接修改数据即可,可分离数据操作到
import Foundation
struct UserModel:Identifiable,Codable {
var id = whatever()//数据区分标识符
let name : String
let type:String
let number:String
}
class UserModels:ObservableObject{//ObservableObject:标记为能够被观察的对象
@Published var dataList:[UserModel]{
didSet{//添加数据
// 通过userdefault进行本地存储
if let data = try? JSONEncoder().encode(dataList){
UserDefaults.standard.set(data, forKey: "allUsers")
}
}
}
// 取出数据
init() {
if let data = UserDefaults.standard.data(forKey: "allUsers"),
let models = try? JSONDecoder().decode([UserModel].self, from: data){
self.dataList = models
}
else{//第一次打开app
dataList = [//使用public公开
UserModel(name: "小姐姐", type: "同学", number: "12312312312"),
UserModel(name: "小老弟", type: "家人", number: "3333333333")
]
}
}
// 添加数据
}
控制器层代码 ContentView.swift
注意:
- 使用属性监听
监听数值变化时,在模型层要遵循ObservableObject协议,将数据标记为能够被观察的对象
在使用时声明要在属性钱添加@ObservedObject包装器 - 使用滑动删除功能要注意
List的封装过于完善,使用滑动删除时需要自行手动通过ForEach遍历数据而不能将数据作为参数传入交给List组件处理
import SwiftUI
struct ContentView: View {
// 复杂数据存入userdefault要进行编码,UserModel类必须支持Codable协议
@State private var sheetController = false
@ObservedObject var userModels = UserModels() //被观察对象属性包装器
var body: some View {
NavigationView{
//List封装过深,如果想使用滑动删除功能则需要配合ForEach自己手动循环
List{//以name作为区分符
ForEach(userModels.dataList){
model in
HStack{
VStack(alignment: .leading){
Text(model.name).font(.headline).foregroundColor(.red)
Text(model.type)
}
Spacer()
Text(model.number)
}
}
.onDelete(perform: remove)//返回闭包函数
}
.navigationBarTitle("电话本")
.navigationBarItems(trailing:
Button(action: {
self.sheetController = true
}){
Image(systemName: "plus")
}
)
.sheet(isPresented: $sheetController) {
AddView(userModels: self.userModels)
}
// .onAppear(){//界面出现时调用
// if let data = UserDefaults.standard.data(forKey: "allUsers"),
// let allUsers = try? JSONDecoder().decode([UserModel].self, from: data){
// // 解码数据
// self.userModels.dataList = allUsers
// }
// }
// .navigationBarItems(trailing: )
}
}
// 分离数据操作,
func remove(index:IndexSet){
self.userModels.dataList.remove(atOffsets: index)//删除指定下标数据
//删除userdefault缓存
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
弹出控制器 AddView.swift
注意:
- 关闭sheet弹出控制器时要通过Environment包装器来获取弹出窗体
@Environment(\.presentationMode) var presentationMode
import SwiftUI
struct AddView: View {
@State private var name = ""
@State private var typeIndex = 0
@State private var number = ""
let types = ["家人","朋友","同事","学生"]
@ObservedObject var userModels : UserModels
// Enviroment属性包装器(用来获取弹出视图)
@Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView{
Form{
TextField("姓名", text: $name)
Picker("类别", selection: $typeIndex) {
ForEach(types.indices, id: \.self){
Text(self.types[$0])
}
}
TextField("号码", text: $number)
}
.navigationBarTitle("添加号码")
.navigationBarItems(trailing: Button("save"){
//添加数据
self.userModels.dataList.append(UserModel(name: self.name, type: self.types[self.typeIndex], number: self.number))
self.presentationMode.wrappedValue.dismiss()//关闭sheet空间
})
}
}
}
struct AddView_Previews: PreviewProvider {
static var previews: some View {
AddView(userModels: UserModels())
}
}