在 Firestore 的 ForEach 中显示时,如何将按钮选择列表保存回 Firebase - SwiftUI

我试图允许用户创建自定义锻炼,我想将所有内容保存到他们自己的用户文档中的 firebase 中,包括锻炼名称、时间和练习。

我可以轻松保存名称,但我不确定如何将练习作为选定行保存回 Firestore。我在 HStack 中展示了 ForEach 的练习以进行更多定制。和右侧的按钮切换 检查练习的真假。

我想做两件事。 1)限制他们可以选择的练习数量为4,然后将他们选择的练习写到firebase(包括练习标题,练习图片和练习gif)。

我认为按钮需要一些 id 或索引或某种方式让它知道哪些已被选中,所以当我说要写入 Firestore 时,它​​只写入选定的 id 或索引。

我不确定如何告诉应用将所选行写入 Firebase。

struct WorkoutBuilder: View {
   @Environment(\.presentationmode) var presentationmode
   @State var workoutName = ""
   @ObservedObject var customWorkoutModel = CustomWorkoutModel()
 
   var body: some View {
       
       VStack(alignment: .leading,spacing: 10){
           HStack(alignment: .top){
               Button(action: goBack) {
                   Image(systemName: "chevron.left")
                       .font(.system(size: 23,weight: .bold,design: .rounded))
                       .foregroundColor(.black)
                       .padding(.top,10)
               }
               Spacer()
           }
           .padding(.horizontal,10)
           
           Text("Name")
               .font(.title2)
               .fontWeight(.semibold)
           
           RoundedRectangle(cornerRadius: 10)
               .foregroundColor(Color("sweatGray"))
               .overlay(
                   TextField("",text: self.$workoutName)
                       .foregroundColor(.black)
                       .autocapitalization(.none)
                       .disableAutocorrection(true)
                       .padding(.horizontal,10)
               )
               .frame(maxWidth: .infinity,maxHeight: 50)
               .padding(.bottom,10)
           
           Text("Layout")
               .font(.title2)
               .fontWeight(.semibold)
           
           HStack{
               RoundedRectangle(cornerRadius: 10)
                   .foregroundColor(Color("sweatGray"))
                   .overlay(
                       Text("20s")
                   )
                   .frame(maxWidth: .infinity,maxHeight: 50)
               
               RoundedRectangle(cornerRadius: 10)
                   .foregroundColor(Color("sweatGray"))
                   .overlay(
                       Text("40s")
                   )
                   .frame(maxWidth: .infinity,maxHeight: 50)
           }
           
           Text("x 4 exercises x 4 rounds")
               .frame(alignment: .center)
           
           Text("Exercises")
               .font(.title2)
               .fontWeight(.semibold)
           
           ScrollView(showsIndicators: false) {
               
               ForEach(customWorkoutModel.customs,id: \.self) { custom in
                   
                   CustomRow(image: custom.image,title: custom.title,gif: custom.gif)
               }
           }
           
           Button(action: {
               
               addCustomWorkout()
               self.presentationmode.wrappedValue.dismiss()
               
           }) {
               
               Text("Save Workout")
                   .fontWeight(.bold)
                   .foregroundColor(.white)
                   .frame(maxWidth: .infinity,maxHeight: 50)
                   .background(Color("sweatBlue"))
                   .cornerRadius(10)
           }
       }
       .padding(.horizontal,10)
       
       .onAppear() {
           self.customWorkoutModel.fetchCustomWorkoutData()
       }
       
   }
   
   // Back Button Function
   func goBack(){
       self.presentationmode.wrappedValue.dismiss()
   }
   
   // write custom workout to frestore
   func addCustomWorkout() {
       
       let db = Firestore.firestore()
       
       db.collection("users").document(Auth.auth().currentUser?.uid ?? "").collection("CustomWorkout").document(self.workoutName).setData([
           
           "date" : Timestamp(date: Date()),"title" : self.workoutName,"classes" : 1,"hours" : 3,//whatever the workout is set as
           "points" : 55,"exerciseoneName":  // I want to save the name of a selected exercise
       ])
   }
}

自定义行

    
    var image : String
    var title : String
  //  var gif : String
    
    @State var selected = ""
    @State var gif = ""
    
    @State private var selectedExercise: Bool = false
    
    var body: some View {
        HStack{
                
                AnimatedImage(url: URL(string: image))
                    .resizable()
                    .scaledToFill()
                    .frame(width: 80)
                
                
                Text(title)
                    .font(.title3)
                
                Spacer()
                
                Button(action: {
                    
                    self.selectedExercise.toggle()
                    self.selected = image // I thought I might be able to save it this way using a string but,no!
                    self.selected = title
                    self.selected = gif
                    
                }) {
                
                    Image(systemName: self.selectedExercise == true ? "checkmark.circle.fill" : "checkmark.circle" )
            }
                  //  .foregroundColor(selectedExercise ? Color("sweatBlack") : Color.blue)
                
            
            .padding(.trailing,10)
        }
        .frame(height: 80)
        .clipped()
        .background(Color("sweatGray"))
        .cornerRadius(10)
    }
}
struct Custom : Identifiable,Hashable {
    
    var id : String = UUID().uuidString
    var title : String
    var image : String
    var gif : String
    
}

App View Screen Shot

kirecetycike 回答:在 Firestore 的 ForEach 中显示时,如何将按钮选择列表保存回 Firebase - SwiftUI

您可能应该将您选择的项目存储在 CustomRow 上方一级,并将选择向下传递到该行。

我将选定的项目 ID 存储在视图模型中,然后将闭包传递给更改选择的 CustomRow

选择更改后,您可以将 Set 写入 Firestore。我假设您只想将 id 列表存储到 Firestore,但理论上,您可以存储整个模型。由于您在评论中说您已经可以保存到 Firestore,因此我省略了该代码。


class CustomWorkoutModel : ObservableObject {
    @Published var customs: [Custom] = [.init(title: "Test",image: "test",gif: "test")]
    @Published var selectedCustomIDs: Set<String> = [] //could add a didSet here to write to firestore,or watch with Combine

    func changeSelection(id: String,selected: Bool) {
        if selected {
            selectedCustomIDs.insert(id)
        } else {
            selectedCustomIDs.remove(id)
        }
    }
    
    var selectedCustoms : [Custom] {
        selectedCustomIDs.compactMap { id in customs.first { custom in
            custom.id == id
        }}
    }
}

struct Custom : Identifiable,Hashable {
    
    var id : String = UUID().uuidString
    var title : String
    var image : String
    var gif : String
    
}

struct WorkoutBuilder: View {
    @Environment(\.presentationMode) private var presentationMode
    @State private var workoutName = ""
    @ObservedObject private var customWorkoutModel = CustomWorkoutModel()
    
    var body: some View {
        
        VStack(alignment: .leading,spacing: 10){
            
            ScrollView(showsIndicators: false) {
                
                ForEach(customWorkoutModel.customs,id: \.self) { custom in
                    
                    CustomRow(image: custom.image,title: custom.title,gif: custom.gif,selected: customWorkoutModel.selectedCustomIDs.contains(custom.id),changeSelection: { selected in
                                customWorkoutModel.changeSelection(id: custom.id,selected: selected)
                    })
                }
                
                Button(action: {
                    
                    addCustomWorkout()
                    self.presentationMode.wrappedValue.dismiss()
                    
                }) {
                    
                    Text("Save Workout")
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .frame(maxWidth: .infinity,maxHeight: 50)
                        .background(Color("sweatBlue"))
                        .cornerRadius(10)
                }
            }
            .padding(.horizontal,10)
            
            .onAppear() {
                //self.customWorkoutModel.fetchCustomWorkoutData()
                print("Get data")
            }
        }
    }
    
    // Back Button Function
    func goBack(){
        self.presentationMode.wrappedValue.dismiss()
    }
    
    // write custom workout to frestore
    func addCustomWorkout() {
        let selected = customWorkoutModel.selectedCustoms
    }
}

struct CustomRow : View {
    var image : String
    var title : String
    var gif: String
    var selected : Bool
    var changeSelection: (Bool) -> Void
    
    var body: some View {
        HStack{
            Text("Image")
            Text(title)
                .font(.title3)
            
            Spacer()
            
            Button(action: {
                self.changeSelection(!selected)
                
            }) {
                Image(systemName: selected ? "checkmark.circle.fill" : "checkmark.circle" )
            }
            //  .foregroundColor(selectedExercise ? Color("sweatBlack") : Color.blue)
            
            .padding(.trailing,10)
        }
        .frame(height: 80)
        .clipped()
        .background(Color("sweatGray"))
        .cornerRadius(10)
    }
}
本文链接:https://www.f2er.com/1119.html

大家都在问