一同养成写作习气!这是我参与「日新计划 4 月更文挑战」的第16天,点击检查活动概况。
今日职言:商业环境的改动是敏捷且规律莫测的,你要做的是,一旦决定了就当即去做。
在本章中,咱们将根据List
列表的基本运用办法上,进阶学习List
列表的更多用法。
本章节将分成3个部分讲解。
1、onDelete
滑动删去和onMove
拖动排序
2、ContextMenu
上下文菜单
3、ActionSheets
弹窗的运用
那咱们开端吧。
榜首部分:onDelete滑动删去和onMove拖动排序
首先,咱们先创立一个新项目,命名为SwiftUIList02
。
咱们创立一个简略的列表,这儿引证之前的List
创立的代码。
完好代码如下:
import SwiftUI
struct Message: Identifiable {
var id = UUID()
var name: String
var image: String
}
// 界说数组,寄存数据
var Messages = [Message(name: "这是微信", image: "weixin"),Message(name: "这是QQ", image: "qq"),Message(name: "这是微博", image: "weibo"),Message(name: "这是手机", image: "phone"),Message(name: "这是邮箱", image: "mail"),]
struct ContentView: View {
var body: some View {
// 列表
List {
ForEach(Messages) { Message in
HStack {
Image(Message.image)
.resizable()
.frame(width: 40, height: 40)
.cornerRadius(5)
Text(Message.name)
.padding()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
这儿咱们运用了List
列表和ForEach
循环的办法建立了一个列表。
运转后的作用如下:
完成单条List
列表数据的滑动删去,咱们需求调用.onDelete(perform:XXXX)
修饰符,它是ForEach
的修饰符,用来删去List中的一条条数据;
perform
中引证的是删去的办法,咱们界说一个删去办法为deleteRow
,详细完成办法如下:
//滑动删去办法
func deleteRow(at offsets: IndexSet) {
Messages.remove(atOffsets: offsets)
}
在deleteRow
删去列的办法中,咱们接纳单一的IndexSet
类型的参数,它是用来定位要删去的列的方位的。
然后调用remove(atOffsets:XXXX)
办法来删去Messages
数组中的被定位的特定项。
这样咱们就可以完成列表的滑动删去,运转模拟器,点击一行向右滑动,咱们就可以完成删去一行数据。
科普一个知识点。
咱们运转的时分会发现,咱们滑动删了1行,体系主动又“创立”了一行回来。
这是因为每次咱们删去List
中特定的数据项时,体系会主动更新UI,而更新的数据源是咱们创立的Messages
数组。
也就是说,每次删去后,体系从头“渲染
”页面,但Messages
数组数据没有改动,也就删去了啥,就恢复了啥,就变成了怎样也删去不了了。
咱们期望的是,删去了特定的数据项时,Messages
数组的值也需求同步被更改。
因此,咱们有必要让SwiftUI
监控特点,并在特点值发生改动时更新UI。咱们运用@State
界说数据:
@State var messagesItems = Messages
并且将ForEach
循环的数据源由Messages
数组,变为咱们用@State
界说的messagesItems
,一起在deleteRow
办法中,操作remove
的目标也换成messagesItems
数组。
这样,咱们每次删去数组特定项的时分,messagesItems
数组就知道咱们删去了什么数据,并且“记住”它,在UI改写的时分,ForEach
就根据messagesItems
数组内的内容遍历数据。
好了,咱们完成了List
页面的滑动删去操作了。
再弥补一个知识点。
如果咱们给List
列表创立导航栏,还可以运用SwiftUI
现已封装好的EditButton
修改按钮,然后完成列表快速进入修改状况,这在Apple
自家的备忘录中可以看到。
当咱们点击Edit
按钮时,按钮文字会变成done
,一起List
列表都变成可删去的形式。
NavigationView {
// 列表
List {
ForEach(messagesItems) { Message in
HStack {
Image(Message.image)
.resizable()
.frame(width: 40, height: 40)
.cornerRadius(5)
Text(Message.name)
.padding()
}
}.onDelete(perform: deleteRow)
}.navigationBarItems(trailing: EditButton())
}
再延伸地弥补一个知识点。
List
列表修改形式下,除了删去之前,还可以针对于数据项进行拖动排序,咱们用的是.onMove(perform:XXXX)
修饰符,它也是ForEach
的修饰符,用来完成List
列表的拖动单条数据的改动它的排序顺序;
NavigationView {
// 列表
List {
ForEach(messagesItems) { Message in
HStack {
Image(Message.image)
.resizable()
.frame(width: 40, height: 40)
.cornerRadius(5)
Text(Message.name)
.padding()
}
}
.onDelete(perform: deleteRow)
.onMove(perform: moveItem)
}.navigationBarItems(trailing: EditButton())
}
perform
中引证的是排序的办法,咱们界说一个删去办法为moveItem
,详细完成办法如下:
// 拖动排序办法
func moveItem(from source: IndexSet, to destination: Int) {
messagesItems.move(fromOffsets: source, toOffset: destination)
}
同样,咱们接纳单一的IndexSet
类型的参数,它是用来定位要排序的列的方位。
然后它的排序数值为Int
类型,简略来说,初始的排序是0、1、2、3、4
,假设咱们把3
拖动到0
,那么体系将主动更新从头排列顺序。
然后完成排序的作用。
快来试试吧!
第二部分:ContextMenu上下文菜单
ContentMenu
上下文菜单是iOS13
引证的一个新功能,作用为长按列表时,弹出一个悬浮窗口,用于方便操作。
iPhone
傍边存在很多这样的交互,示例:长按体系设置,翻开方便操作弹窗。
完成ContentMenu
上下文菜单的办法也很简略,运用.contentMenu
修饰符,在修饰符里边构建需求展示或者操作的内容。
这儿咱们测验做一个长按删去的操作,长按列表的一个项目,弹出上下文ContentMenu
菜单,里边是一个删去按钮,点击按钮,删去指定行的数据。
.contextMenu {
Button(action: {
// 点击删去
}) {
HStack {
Text("删去")
Image(systemName: "trash")
}
}
}
然后,咱们完成下删去的操作,会有些复杂,请耐心查阅。
它不像咱们运用ForEach
运用的.onDelete
删去修饰符的办法不相同,ContentMenu
上下文菜单没有索引定位到特定的数据项,也就不知道咱们点击选中的是哪一条数据。
这就需求咱们自己定位到Messages
数组里边的Message
的id
,这样咱们就可以经过id
定位到是数组中的哪一条数据了。
办法如下:
//删去的办法
func delete(item Message: Message) {
if let index = self.messagesItems.firstIndex(where: { $0.id == Message.id }) {
self.messagesItems.remove(at: index)
}
}
咱们界说了一个delete
的函数办法,接纳了一个Message
目标,并在Messages
数组中搜索Message
目标的索引。
为了找到Message
目标的索引,咱们调用firstIndex
函数循环遍历数组,并将给定Messages
的id
与数组中的id
进行比较。
如果有id
相同,则firstIndex
函数回来Messages
数组的索引。
这样咱们就知道长按的是哪一条数据了!
接下来,咱们就可以经过调用remove(at:XXXX)
修饰符从Messages
数组中删去对应的数据项。
self.delete(item: Message)
咱们运转一下模拟器,长按,体系会给出ContentMenu
上下文菜单,它是一个删去按钮,咱们点击删去按钮,该行数据就被删去了。
完好代码如下:
import SwiftUI
struct Message: Identifiable {
var id = UUID()
var name: String
var image: String
}
// 界说数组,寄存数据
var Messages = [Message(name: "这是微信", image: "weixin"),Message(name: "这是QQ", image: "qq"),Message(name: "这是微博", image: "weibo"),Message(name: "这是手机", image: "phone"),Message(name: "这是邮箱", image: "mail"),]
struct ContentView: View {
// 界说数组
@State var messagesItems = Messages
var body: some View {
NavigationView {
// 列表
List {
ForEach(messagesItems) { Message in
HStack {
Image(Message.image)
.resizable()
.frame(width: 40, height: 40)
.cornerRadius(5)
Text(Message.name)
.padding()
}
.contextMenu {
Button(action: {
// 点击删去
self.delete(item: Message)
}) {
HStack {
Text("删去")
Image(systemName: "trash")
}
}
}
}
.onDelete(perform: deleteRow)
.onMove(perform: moveItem)
}.navigationBarItems(trailing: EditButton())
}
}
//删去的办法
func delete(item Message: Message) {
if let index = self.messagesItems.firstIndex(where: { $0.id == Message.id }) {
self.messagesItems.remove(at: index)
}
}
// 滑动删去办法
func deleteRow(at offsets: IndexSet) {
messagesItems.remove(atOffsets: offsets)
}
// 拖动排序办法
func moveItem(from source: IndexSet, to destination: Int) {
messagesItems.move(fromOffsets: source, toOffset: destination)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
第三部分:ActionSheets弹窗的运用
弹窗傍边,咱们在之前的章节学习了ModelView
弹窗,这儿咱们再拓宽一种弹窗形式,叫做.actionSheet
。
它算是.sheet
的另一种形式,常用在用户敏感操作的二次承认,但又不像Alerts
正告弹窗那么严肃,属于一般强调。
.actionSheet
和Alerts
正告弹窗的完成方式大体相同。
.actionSheet(isPresented:$showActionSheet) {
//ActionSheet结构体
}
咱们还是运用isPresented
触发,咱们界说一个变量showActionSheet
的状况,初始状况是false
。
@State varshowActionSheet = false
接下来,咱们完成下ActionSheet
结构体:
// ActionSheet弹窗
.actionSheet(isPresented: self.$showActionSheet) {
ActionSheet(
title: Text("你确定要删去此项吗?"),
message: nil,
buttons: [
.destructive(Text("删去"), action: {
//点击删去
}),
.cancel(Text("撤销")
])
}
下面,咱们做一个“风趣”的操作。
咱们承接上一部分的内容,长按列表,弹出一个ContentMenu
上下文菜单,里边是一个删去按钮,点击删去按钮,翻开ActionSheet
弹窗,里边又是一个删去按钮,点击ActionSheet
弹窗内的删去按钮,删去列表的数据项。
咱们就完成了根据ActionSheet
弹窗的删去操作啦!
完好代码如下:
import SwiftUI
struct Message: Identifiable {
var id = UUID()
var name: String
var image: String
}
// 界说数组,寄存数据
var Messages = [
Message(name: "这是微信", image: "weixin"),
Message(name: "这是QQ", image: "qq"),
Message(name: "这是微博", image: "weibo"),
Message(name: "这是手机", image: "phone"),
Message(name: "这是邮箱", image: "mail"),
]
struct ContentView: View {
// 界说数组
@State var messagesItems = Messages
@State var showActionSheet = false
var body: some View {
NavigationView {
// 列表
List {
ForEach(messagesItems) { Message in
HStack {
Image(Message.image)
.resizable()
.frame(width: 40, height: 40)
.cornerRadius(5)
Text(Message.name)
.padding()
}
// 上下文菜单
.contextMenu {
Button(action: {
// 点击翻开ActionSheet弹窗
self.showActionSheet.toggle()
}) {
HStack {
Text("删去")
Image(systemName: "trash")
}
}
}
// ActionSheet弹窗
.actionSheet(isPresented: self.$showActionSheet) {
ActionSheet(
title: Text("你确定要删去此项吗?"),
message: nil,
buttons: [
.destructive(Text("删去"), action: {
//点击删去
self.delete(item: Message)
}),
.cancel(Text("撤销"))
])
}
}
.onDelete(perform: deleteRow)
.onMove(perform: moveItem)
}.navigationBarItems(trailing: EditButton())
}
}
// 删去的办法
func delete(item Message: Message) {
if let index = messagesItems.firstIndex(where: { $0.id == Message.id }) {
messagesItems.remove(at: index)
}
}
// 滑动删去办法
func deleteRow(at offsets: IndexSet) {
messagesItems.remove(atOffsets: offsets)
}
// 拖动排序办法
func moveItem(from source: IndexSet, to destination: Int) {
messagesItems.move(fromOffsets: source, toOffset: destination)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
快来动手试试吧!
如果本专栏对你有协助,无妨点赞、评论、重视~