Передача списка между представлениями в SwiftUi

Я делаю приложение со списком ToDo самостоятельно, чтобы попытаться познакомиться с разработкой для iOS, и у меня возникла одна проблема:

У меня есть отдельный Viewсвязана для входа в новую задачу с. Вот код этого файла:

      import SwiftUI

struct AddTask: View {
     @State public var task : String = ""
     @State var isUrgent: Bool = false // this is irrelevant to this problem you can ignore it

    
    var body: some View {
        VStack {
            VStack(alignment: .leading) {
                Text("Add New Task")
                    .bold()
                    .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/)
                TextField("New Task...", text: $task)
                Toggle("Urgent", isOn: $isUrgent)
                    .padding(.vertical)
                Button("Add task", action: {"call some function here to get what is 
in the text field and pass back the taskList array in the Content View"})
               
                 
                
            }.padding()
            Spacer()
        }
    }
    
}


struct AddTask_Previews: PreviewProvider {
    static var previews: some View {
        AddTask()
    }
}

Итак, что мне нужно взять введенную переменную задачи и вставить ее в массив, который будет отображаться в списке в моем основном файле.

Вот файл для справки:

      import SwiftUI

struct ContentView: View {
    @State var taskList = ["go to the bakery"]
    
    struct AddButton<Destination : View>: View {

        var destination:  Destination

        var body: some View {
            NavigationLink(destination: self.destination) { Image(systemName: "plus") }
        }
    }
    
    var body: some View {
        VStack {
            NavigationView {
                List {
                    ForEach(self.taskList, id: \.self) {
                    item in Text(item)
                    }
                }.navigationTitle("Tasks")
                .navigationBarItems(trailing: HStack { AddButton(destination: AddTask())})
            }
            
        }
        
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
  }
}

Мне нужна функция для выполнения задачи, введенной в TextField, и передать его обратно в массив в ContentView для отображения в List для пользователя

-Спасибо за помощь

2 ответа

Вы можете добавить свойство закрытия в свой обратный вызов, когда пользователь нажимает Add Task. Именно так:

      struct AddTask: View {
  var onAddTask: (String) -> Void // <-- HERE
  @State public var task: String = ""
  @State var isUrgent: Bool = false

  var body: some View {
    VStack {
      VStack(alignment: .leading) {
        Text("Add New Task")
          .bold()
          .font(.title)
        TextField("New Task...", text: $task)
        Toggle("Urgent", isOn: $isUrgent)
          .padding(.vertical)
        Button("Add task", action: {
          onAddTask(task)
        })
      }.padding()
      Spacer()
    }
  }

}

Затем в ContentView:

      .navigationBarItems(
    trailing: HStack {
      AddButton(
        destination: AddTask { task in
            taskList.append(task)
        }
      )
  }
)

jn_pdx предоставляет хорошее решение, передавая BindingtaskList в. Но я думаю AddTaskиспользуется для добавления новой задачи, поэтому он должен фокусироваться только на новой задаче, а не на полном списке задач.

Вы можете использовать @Bindingдля передачи ссылки из родительского представления в дочернее представление, которое может быть изменено дочерним элементом. См. Приложенный код и найдите <-- Here линий.

      
struct ContentView: View {
    @State var taskList = ["go to the bakery"]
    
    struct AddButton<Destination : View>: View {
        
        var destination:  Destination
        
        var body: some View {
            NavigationLink(destination: self.destination) { Image(systemName: "plus") }
        }
    }
    
    var body: some View {
        VStack {
            NavigationView {
                List {
                    ForEach(self.taskList, id: \.self) {
                        item in Text(item)
                    }
                }.navigationTitle("Tasks")
                .navigationBarItems(trailing: HStack { AddButton(destination: AddTask(taskList: $taskList))}) //<-- Here
            }
            
        }
    }
    
}


struct AddTask: View {
    @Binding var taskList : [String] //<-- Here
    
    @State private var task : String = ""
    @State private var isUrgent: Bool = false // this is irrelevant to this problem you can ignore it
    
    @Environment(\.presentationMode) private var presentationMode
    
    var body: some View {
        VStack {
            VStack(alignment: .leading) {
                Text("Add New Task")
                    .bold()
                    .font(.title)
                TextField("New Task...", text: $task)
                Toggle("Urgent", isOn: $isUrgent)
                    .padding(.vertical)
                Button("Add task", action: {
                    taskList.append(task) //<-- Here
                    presentationMode.wrappedValue.dismiss()
                })
            }.padding()
            Spacer()
        }
    }
    
}


struct AddTask_Previews: PreviewProvider {
    static var previews: some View {
        AddTask(taskList: .constant([]))  //<-- Here
    }
}

Я также использовал presentationMode чтобы закрыть дочернее представление после добавления нового элемента - это, конечно, необязательно и может быть удалено, если вы не хотите такого поведения.

Другие вопросы по тегам