问题的背景:我正在创建一个简单的应用,该应用将活动数据存储在结构中。我创建了一个自定义视图,称为“ CardView”(保存在项目中的单独文件中),该视图将显示在基本ContentView上。 CardView填充有Text标签,该Text标签将绑定到上述活动数据结构中的相应数据。 ForEach根据存在的活动“项目”处理这些卡片的动态创建。请参阅以下代码...
struct ActivityItem: Identifiable, Codable {
let id = UUID()
let name: String
let description: String
let type: String
var amount: Int
}
class AppData: ObservableObject {
@Published var activites: [ActivityItem] {
didSet {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(activites) {
UserDefaults.standard.set(encoded, forKey: "Activites")
}
}
}
init() {
if let foundActivities = UserDefaults.standard.data(forKey: "Activites") {
let decoder = JSONDecoder()
if let decoded = try? decoder.decode([ActivityItem].self, from: foundActivities) {
self.activites = decoded
return
}
}
self.activites = []
}
}
struct ContentView: View {
@ObservedObject var appData = AppData()
@State private var showingAddActivity = false
@State private var showingMoreInfo = false
var body: some View {
NavigationView {
ZStack {
Rectangle()
.fill(Color(.gray))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
ScrollView {
VStack(spacing: 50) {
ForEach(appData.activites) { activity in
CardView(appData: self.appData)
}
}
}
// Below held in separate file
struct CardView: View {
@ObservedObject var appData: AppData
@State private var showingMoreInfo = false
var body: some View {
ZStack {
Rectangle()
.fill(Color(.gray))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
RoundedRectangle(cornerRadius: 20)
.fill(Color(.black))
.frame(width: 325, height: 180)
VStack {
Text("Name")
.font(.title)
Text("Description")
Text("Type")
Text("Amount")
}
.sheet(isPresented: $showingMoreInfo) {
Text("View")
}
}
}
}
问题:尽管后来通过使用@Binding和利用@Environmental进行了多次尝试,无数小时和错误,但我无法将数据从ForEach中的当前ActivityItem传递到CardView中,以用于替换Text标签中的String占位符(即名称,类型,金额)。尝试创建和使用绑定时,例如$ activity.name之类的绑定,它声明“ activity”不能成为绑定。我究竟做错了什么?如何以最简单的方式让每个活动将其数据传递给CardView结构,填充这些Text标签,然后在ContentView“主屏幕”上创建自己,然后对ForEach迭代中的所有其余对象重复?有什么重要的注意事项要记住,以免将来发生此类问题?我必须补充一点,如果我将CardView代码直接放入ContentView中而不在ForEach中调用CardView(),则可以轻松地引用数据;仅在使用CardView结构时才成为问题(可重用性和代码混乱的长期目标)。谢谢您的帮助!
答案 0 :(得分:0)
我假设您的意思是以下内容(已通过Xcode 12 / iOS 14测试)
struct ActivityItem: Identifiable, Codable {
var id = UUID()
var name: String // << made `var` here and other to allow write
var description: String
var type: String
var amount: Int
}
class AppData: ObservableObject {
@Published var activites: [ActivityItem] {
didSet {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(activites) {
UserDefaults.standard.set(encoded, forKey: "Activites")
}
}
}
init() {
if let foundActivities = UserDefaults.standard.data(forKey: "Activites") {
let decoder = JSONDecoder()
if let decoded = try? decoder.decode([ActivityItem].self, from: foundActivities) {
self.activites = decoded
return
}
}
self.activites = []
}
}
struct ContentView: View {
@ObservedObject var appData = AppData()
@State private var showingAddActivity = false
@State private var showingMoreInfo = false
var body: some View {
NavigationView {
ZStack {
Rectangle()
.fill(Color(.gray))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
ScrollView {
VStack(spacing: 50) {
ForEach(appData.activites.indices, id: \.self) { i in
CardView(item: $appData.activites[i]) // binding here
}
}
}
}
}
}
}
// Below held in separate file
struct CardView: View {
@Binding var item: ActivityItem // binding here
@State private var showingMoreInfo = false
var body: some View {
ZStack {
Rectangle()
.fill(Color(.gray))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
RoundedRectangle(cornerRadius: 20)
.fill(Color(.black))
.frame(width: 325, height: 180)
VStack {
TextField("Name", text: $item.name) // edit here
.font(.title)
Text("Description")
Text("Type")
Text("Amount")
}
.sheet(isPresented: $showingMoreInfo) {
Text("View")
}
}
}
}