SwiftUI iOS15 Binding ForEach está desestimando el teclado de TextField.
Como se menciona en WWDC21 “Novedades en SwiftUI”, ahora es posible manejar el binding dentro de ForEach, pero tengo un problema con TextField, si agrego un carácter, el teclado desaparece.
struct TESTVIEW: View {
public struct MyTask: Identifiable, Codable, Hashable {
public var id: UUID = UUID()
var title: String = ""
}
@State var tasks: [MyTask] = []
var body: some View {
VStack {
Text("NEW")
List {
ForEach ($tasks, id:\.self) { $task in
TextField("Click", text: $task.title)
}
.onDelete(perform: delete)
Button(action: {
tasks.append(MyTask())
}) {
Label("New task", systemImage: "plus.circle.fill")
}
.padding()
.accentColor(.white)
}
Text("OLD")
List {
ForEach (tasks.indices, id:\.self) { idx in
let bindingTask = Binding(get: {tasks[idx]},set: {value in tasks[idx] = value})
TextField("Click", text: bindingTask.title)
}
.onDelete(perform: delete)
Button(action: {
tasks.append(MyTask())
}) {
Label("New task", systemImage: "plus.circle.fill")
}
.padding()
.accentColor(.white)
}
}
.preferredColorScheme(.dark)
}
func delete(at offsets: IndexSet) {
tasks.remove(atOffsets: offsets)
}
}
struct TESTVIEW_Previews: PreviewProvider {
static var previews: some View {
TESTVIEW()
}
}
¿Alguna sugerencia?
davy.ai
Basado en el código proporcionado, parece que el problema con el teclado que se oculta cuando se agrega un carácter al
TextField
se debe al uso de$task.title
como enlace para elTextField
.Una posible solución a este problema es crear una variable
@State
separada para almacenar el texto ingresado en elTextField
y luego usar esa variable de estado para actualizar el objetoMyTask
dentro del bucleForEach
.Aquí tienes un fragmento de código actualizado que muestra este enfoque:
En este código actualizado, hemos agregado una nueva variable
@State
llamadanewTaskTitle
, que se utiliza para guardar el texto ingresado por el usuario en elTextField
que se utiliza para crear una nueva tarea.También hemos agregado un modificador
.onChange
a ambas vistasList
, que se activa cuando la variable de estadonewTaskTitle
cambia. Dentro del cierre, verificamos si el nuevo título no está vacío y, de ser así, creamos un nuevo objetoMyTask
con el título proporcionado y lo agregamos al arraytasks
. También restablecemos la variablenewTaskTitle
a una cadena vacía para borrar elTextField
.Para usar la variable de estado
newTaskTitle
, hemos actualizado el primer bucleForEach
para usar$tasks
, que nos proporciona enlaces a los objetosMyTask
en el array. Dentro de este bucle, simplemente usamos el enlace altitle
para actualizar el texto delTextField
.Para el segundo bucle
ForEach
, hemos creado una funciónbinding(for:)
que toma unBinding<mytask>
y devuelve unBinding<string>
que podemos usar para actualizar el texto delTextField
. Dentro de la función, usamos la propiedadwrappedValue
delBinding<mytask>
para acceder al objetoMyTask
y luego usamos eso para crear un nuevoBinding<string>
que actualiza la propiedadtitle
del objetoMyTask
.En general, estos cambios deberían permitirte administrar enlaces dentro de
ForEach
y al mismo tiempo poder ingresar texto en elTextField
sin ocultar el teclado.