绑定两个 ForEach 循环以更新每个项目单元格
Posted
技术标签:
【中文标题】绑定两个 ForEach 循环以更新每个项目单元格【英文标题】:Binding two ForEach loop to update each item cell 【发布时间】:2021-09-24 01:58:50 【问题描述】:这是我的第二篇文章,我尽可能地需要你的帮助。我正在我的父视图和详细视图上创建一个收藏按钮。我需要两个按钮才能相互对应。当我在父视图的 ForEach 循环上标记为收藏时,我想在我的详细视图中显示该项目是收藏的。此外,我可以从我的详细视图副 vasa 中取消收藏或收藏。我真的很难弄清楚如何绑定这两个 ForEach 循环。下面我提供了一个我的代码示例。如果你想用我的完整代码进行测试,你可以在这里访问它:Making favorite button from several layers and binding two list using EnvironmentObject
struct Data: Identifiable
let id = UUID()
let number: Int
var name1: String
let name2: String
public struct DataList
static var dot = [
Data(number: 1,
name1: "Pasian Phatna",
name2: "Praise God, from whom All Blessings Flow"),
Data(number: 2,
name1: "Itna Kumpi, Ka Tuu-Cing Pa",
name2: "The King of Love My Shephaerd Is (Dominus Regit Me)"),
Data(number: 3,
name1: "Kumpipa Bia Un",
name2: "O Worship the King"),
Data(number: 4,
name1: "Pa Tung Min Than'na Om Hen",
name2: "Gloria Patri (1st Tune)"),
Data(number: 5,
name1: "Pa Tung Min Than'na Om Hen",
name2: "Gloria Patri (2nd Tune)")
]
struct ParentView: View
@State var datas: [Data] = DataList.dot
var body: some View
NavigationView
ScrollView (.vertical, showsIndicators: false)
LazyVStack(spacing: 5)
ForEach (datas, id: \.id) data in
MainData(data: data)
Divider()
.padding(.all)
.navigationBarHidden(true)
.navigationViewStyle(StackNavigationViewStyle())
struct MainData: View
@State var data: Data
@State var selectedFavoriteSong: Bool = false
var body: some View
HStack
Button(action:
self.selectedFavoriteSong.toggle()
, label:
if selectedFavoriteSong
Image(systemName: "suit.heart.fill")
.foregroundColor(.red)
.padding(.horizontal)
else
Image(systemName: "suit.heart")
.padding(.horizontal)
)
Spacer()
Text("\(data.number)")
Spacer()
.padding(.top)
VStack
Text(data.name1)
.font(.title2.smallCaps())
.fontWeight(.bold)
.foregroundColor(.primary)
Text(data.name2)
.font(.title3)
.fontWeight(.medium)
.foregroundColor(.secondary)
.italic()
.padding(.horizontal)
.multilineTextAlignment(.center)
请注意,当我点击搜索图标(此处未显示)时,会弹出下面的 Search()。我的观点是 Search() 不是直接连接到 ParentView() 而是 DetailView() 嵌入在 Search() 中。
struct Search: View
@State var datas: [Data] = DataList.dot
var body: some View
NavigationView
ScrollView (.vertical, showsIndicators: false)
LazyVStack(alignment: .leading, spacing: 10)
ForEach (datas, id: \.id) data in
NavigationLink(
destination: DetailView(data: data),
label:
Text("Search")
)
.padding(.horizontal)
struct DetailView: View
@State var data: Data
@State var selectedFavoriteSong: Bool = false
var body: some View
HStack
Button(action:
self.selectedFavoriteSong.toggle()
, label:
if selectedFavoriteSong
Image(systemName: "suit.heart.fill")
.foregroundColor(.red)
.padding(.horizontal)
else
Image(systemName: "suit.heart")
.padding(.horizontal)
)
Spacer()
Text("\(data.name1)")
Spacer()
.padding(.top)
VStack
Text(data.name2)
.font(.title2.smallCaps())
.fontWeight(.bold)
.foregroundColor(.primary)
.padding(.horizontal)
.multilineTextAlignment(.center)
Spacer()
所以,我想用某种绑定属性连接父视图和详细视图。但这两者是不可能联系起来的。我可以存储
@State var selectedFavoriteSong: Bool = false
在环境对象内。但是当我点击收藏时,ForEach 循环内的所有项目都被选中。请在这个问题上帮助我。如果您需要完整的代码,上面的链接将指向我的第一篇文章。谢谢。
【问题讨论】:
什么是DataList
?它没有在此处或您的其他链接中定义。请尝试在此问题中包含minimal reproducible example,可以将其复制并粘贴到 Xcode 中进行测试。
我将重新发布 DataList 的示例。
【参考方案1】:
我建议将所有数据存储在父视图拥有的 ObservableObject 中,然后可以传递到子视图(显式地或通过EnvironmentObject
):
class DataSource : ObservableObject
@Published var data : [Data] = DataList.dot
@Published var favoritedItems: Set<UUID> = []
func favoriteBinding(forID id: UUID) -> Binding<Bool>
.init
self.favoritedItems.contains(id)
set: newValue in
if newValue
self.favoritedItems.insert(id)
else
self.favoritedItems.remove(id)
例如:
struct ParentView : View
@StateObject var dataSource = DataSource()
var body: some View
VStack
Search(dataSource: dataSource)
请注意,数据源存储已收藏的 ID 列表。它使用自定义绑定,可以将布尔值向下传递到详细视图:
struct Search: View
@ObservedObject var dataSource : DataSource
var body: some View
NavigationView
ScrollView (.vertical, showsIndicators: false)
LazyVStack(alignment: .leading, spacing: 10)
ForEach (dataSource.data, id: \.id) data in
NavigationLink(
destination: DetailView(data: data,
selectedFavoriteSong: dataSource.favoriteBinding(forID: data.id)),
label:
Text(data.name1)
)
.padding(.horizontal)
struct DetailView: View
var data : Data
@Binding var selectedFavoriteSong : Bool
var body: some View
HStack
Button(action:
self.selectedFavoriteSong.toggle()
, label:
if self.selectedFavoriteSong
Image(systemName: "suit.heart.fill")
.foregroundColor(.red)
.padding(.horizontal)
else
Image(systemName: "suit.heart")
.padding(.horizontal)
)
Spacer()
Text("\(data.name1)")
Spacer()
.padding(.top)
VStack
Text(data.name2 ?? "")
.font(.title2.smallCaps())
.fontWeight(.bold)
.foregroundColor(.primary)
.padding(.horizontal)
.multilineTextAlignment(.center)
Spacer()
【讨论】:
原来我的 MainData() 不见了。我必须删除那个吗? 没有。您可以对它应用与我在上面展示的完全相同的原则。只需确保您将数据和绑定传递给它。 每次我返回 ParentView 时,我的应用程序都会崩溃,绑定还没有起作用。但是当你指导我的方法时,我明白了。我认为我的代码太乱了,我需要正确应用您的指导。非常感谢@jnpdx,因为当我需要帮助时,你总是在那里。此外,课堂上的功能对我来说是全新的。我必须研究那个方法。再次感谢您。 @Lian Hmm - 崩溃听起来不太好。但是,是的,一旦你弄清楚如何实现它,使用这种模式可能会帮助你在视图之间有效地共享数据。知道如何编写这些自定义绑定也非常有用。 我找到了崩溃的错误。问题是我必须将 EnvironmentObject 传递给 NavigationView。原来这是 ios 14 的问题。基本上,您提供的答案是有效的。非常感谢。以上是关于绑定两个 ForEach 循环以更新每个项目单元格的主要内容,如果未能解决你的问题,请参考以下文章
将数据从枚举传递到在ForEach循环中触发的sheet中。
如何获取与表连接绑定的 Row datagridview selectedItem 的每个单元格的值?