绑定两个ForEach循环来更新每个item单元格



这是我的第二篇文章,我需要你尽可能多的帮助。我正在父视图和详细视图上创建一个收藏按钮。我需要两个按钮相互配合。当我在父视图的ForEach循环上标记了favorites时,我希望在详细视图中显示已收藏的项目。此外,我可以在详细视图中取消收藏或收藏,反之亦然。我很难弄清楚如何绑定这两个ForEach循环。下面我提供了一个代码示例。如果您想用我的完整代码进行测试,您可以在这里访问它:使用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

在环境对象内。但是当我单击favorite时,ForEach循环中的所有项都被选中。请在这个问题上帮助我。如果你需要一个完整的代码,上面的链接将直接到我的第一篇文章。谢谢你。

我建议将所有数据存储在父视图拥有的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()

}
}

最新更新