【问题标题】:Accessing @State variables in child views from parent views SwiftUI从父视图SwiftUI访问子视图中的@State变量
【发布时间】:2020-11-22 08:35:18
【问题描述】:

我正在尝试从调用该视图的视图访问在视图中标记为@State 的变量。子视图中的这些变量连接到一个文本框。如果我在该文本框中键入并按回车键,然后单击一个按钮,则该按钮位于父视图中,要读取该变量,它会返回一个空字符串。如果我拿那个按钮并将它放在子视图中并做同样的事情,它会打印我在文本框中输入的内容。我对 SwiftUI 很陌生,这可能是一个非常简单的修复方法,但我已经尝试了所有方法。非常感谢任何帮助!

父视图(DetailedView)

struct DetailedView: View {
    
    @Environment(\.managedObjectContext) var moc
    
    var targetMuscle : String = "Chest"
    let today = Date()
    @State public var exerciseCards : [ExerciseCard] = []
    @State public var exercise : String = "Bench Press"
    @State public var exercises : Int = 0
    @State public var showPassedWorkouts : Bool = false
    
    static let taskDateFormat : DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        return formatter
    }()
    
    var body: some View {
        ZStack{
            VStack{
                HStack{
                    VStack{
                        Text(targetMuscle).font(.system(size:40)).fontWeight(.medium)
                        Text("\(today, formatter: Self.taskDateFormat)")
                            .font(.system(size:20))
                    }.frame(width: 250, height: 30, alignment: .topLeading)
                        .navigationBarTitle("")
                        .navigationBarHidden(true)
                        .padding(.bottom, -7)
                    Button(action: {
                        self.showPassedWorkouts.toggle()
                    }) {
                        Text("Passed Workouts")
                            .multilineTextAlignment(.center)
                        
                        
                    }.offset(x: -75, y: 25)
                        .sheet(isPresented: $showPassedWorkouts){
                            PassedWorkoutList()
                    }
                    
                    
                    Button(action: {
                        
                        let workout = Workout(context: self.moc)
                        workout.muscle = self.targetMuscle
                        workout.date = formattedDateString(day: self.today)
                        
                        for number in 0..<self.exerciseCards.count{
                            let exercise = Exercise(context: self.moc)
                            exercise.name = self.exerciseCards[number].exercise
                            for innerNum in 0..<self.exerciseCards[number].tableRows.count{
                                let exerciseSet = ExerciseSet(context: self.moc)
                                exerciseSet.reps = Int16(self.exerciseCards[number].tableRows[innerNum].reps) ?? 0
                                exerciseSet.weight = Int16(self.exerciseCards[number].tableRows[innerNum].weight) ?? 0
                                exerciseSet.set = self.exerciseCards[number].tableRows[innerNum].set
                                exercise.addToExerciseSet(exerciseSet)
                            }
                            workout.addToExercise(exercise)
                        }
                        
                        try? self.moc.save()
                        
                    }) {
                        Text("Finish")
                    }.offset(x: -20, y: 20)
                }.padding(.bottom, 35)
                    .padding(.leading)
                
                
                
                ScrollView{
                    ForEach(0..<exerciseCards.count, id: \.self){ number in
                        self.exerciseCards[number]
                    }
                    
                    
                    Button(action: {
                        self.exerciseCards.append(ExerciseCard())
                    }) {
                        Text("Add Exercise")
                            .frame(minWidth: 325)
                            .padding()
                            .foregroundColor(.white)
                            .background(Color.blue.opacity(0.7))
                            .cornerRadius(20)
                        
                    }.padding(.top)
                        .frame(width: 400)
                }
                
                
            }
        }.background(Color.white)
            
    }
    
}

第一个子视图(ExerciseCard)

struct ExerciseCard: View {
    @State public var exercise : String = ""
    @State public var tableRows : [ExerciseTableRow] = []
    
    var body: some View {
        VStack{
            TextField("Enter Exercise", text: $exercise).textFieldStyle(RoundedBorderTextFieldStyle())
            .frame(width: 300)
            .multilineTextAlignment(.center)
            HStack{
                Group{
                    Text("Set")
                    Text("Weight")
                    Text("Reps")
                }.padding(.horizontal, 30)
                .offset(x: -20, y: 0)
                
            }
            VStack{
                
                ForEach(0..<tableRows.count, id: \.self){ number in
                    self.tableRows[number]
                    
                    
                }
            }.padding(.bottom, 5)
            
            HStack{
                Button(action: {
                    if self.tableRows.count > 1{
                        self.tableRows.remove(at: self.tableRows.count-1)
                    }
                        
                }) {
                    Text("Remove Set")
                        .frame(minWidth: 150)
                        .padding(.vertical, 5)
                        .foregroundColor(.white)
                        .background(Color.red)
                        .cornerRadius(20)
                    
                }
                
                Button(action: {
                    self.tableRows.append(ExerciseTableRow(set: 2, readOnly: false, setWeight: 2, setReps: 2))
                }) {
                    Text("Add Set")
                        .frame(minWidth: 150)
                        .padding(.vertical, 5)
                        .foregroundColor(.white)
                        .background(Color.green)
                        .cornerRadius(20)
                    
                }
                
            }
        }
        .padding()
        .padding(.vertical)
        .background(Color.offWhite)
        .cornerRadius(20)
        .shadow(color: Color.black.opacity(0.2), radius: 10, x:10, y:10)
        .shadow(color: Color.white.opacity(0.7), radius: 10, x:-5, y:-5)
    }
}

第二个子视图(ExerciseTableRow)

struct ExerciseTableRow: View {
    @State public var weight : String = "0"
    @State public var reps : String = "0"
    var set : Int16
    var readOnly : Bool
    var setWeight : Int16
    var setReps : Int16
    var body: some View {
        
        HStack{
            Text(String(set))
                .padding(.trailing, 40)
                .padding(.leading, 10)
            if readOnly == false{
                Group{
                    TextField("0", text: $weight)
                    TextField("0", text: $reps)
                }.textFieldStyle(RoundedBorderTextFieldStyle())
                    .frame(width: 50)
                    .multilineTextAlignment(.center)
                    .keyboardType(.numberPad)
                    .padding(.horizontal, 30)
            }
            else{
                Group{
                    Text(String(setWeight))
                    Text(String(setReps))
                }
                .frame(width: 50)
                    .overlay(
                        RoundedRectangle(cornerRadius: 5)
                            .stroke(Color.black, lineWidth: 1)
                    )
                    .padding(.bottom, 5)
                    .padding(.horizontal, 30)
            }
            
        }
        
        
    }
}

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

    DetailedView 中的 StateExerciseTableRow 中的 ExerciseTableRow 不相关。他们只是碰巧有相同的名字,但他们是不同的。

    要在您的子视图中访问这些变量,您必须将这些值传递给您的子视图。

    您可以将它们存储在一个常量中:

    struct ExerciseCard: View {
        let exercise : String
        let tableRows : [ExerciseTableRow]
    
        // 
    }
    

    并通过传递值来初始化您的视图:

    ExerciseCard(exercise: someString, tableRows: someArray)
    

    如果您希望能够在子视图中更改这些值,您应该在子视图中将它们定义为Bindings:

    struct ExerciseCard: View {
        @Binding public var exercise : String
        @Binding public var tableRows : [ExerciseTableRow]
        //
    }
    

    并初始化它:

    ExerciseCard(exercise: self.$exerciseString, tableRows: self.$tableRowsArray)
    

    不要忘记State 变量名之前的前导$ 以将其作为Binding 传递

    【讨论】:

      【解决方案2】:

      您可以将您的子视图属性声明为@Binding 而不是@State

      struct DetailedView: View {
          ...
          @State public var exercise: String = "Bench Press"
      }
      
      struct ExerciseCard: View {
          @Binding public var exercise: String
          ...
      }
      

      然后将变量从父视图传递给子视图:

      ExerciseCard(exercise: $exercise)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-06
        • 2013-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多