Tenho um SwiftUI List
(no macOS) onde quero exibir alguns TextFields
em cada linha e observar como o foco muda conforme um campo de texto individual é selecionado ou desmarcado. Isso parece funcionar bem se eu apenas tiver a List
exibição pura TextField
em cada linha, mas se eu incorporar TextField
dentro de uma Button
visualização, as notificações de mudança de foco param de funcionar. Quero a funcionalidade de 'botão' para que o usuário possa tocar em qualquer lugar da linha e ter o campo de texto ativado, em vez de tocar exatamente no limite do campo de texto.
Aqui está um código para demonstrar o problema. Se List
você tiver RowView
descomentado (1), então as notificações de mudança de foco funcionam. Se você comentar isso e descomentar RowViewWithButton
(2), então a funcionalidade do botão funciona, mas não consigo mais receber notificações de mudança de foco.
import SwiftUI
// test on macOS target
struct ContentView: View {
@State private var textFields = Array(repeating: "", count: 4)
@FocusState private var focusedField: Int?
var body: some View {
List(0..<4, id: \.self) { index in
// 1. works with focus notification changes
RowView(index: index, text: $textFields[index], focusedField: $focusedField)
// 2. button works, but no focus notifications on text field
//RowViewWithButton(index: index, text: $textFields[index], focusedField: $focusedField)
}
}
}
struct RowView: View {
let index: Int
@Binding var text: String
@FocusState.Binding var focusedField: Int?
var body: some View {
HStack {
Text("Row \(index + 1):")
TextField("", text: $text)
.multilineTextAlignment(.leading)
.focused($focusedField, equals: index)
}
.onChange(of: focusedField) { newFocus in
if newFocus == index {
print("TextField \(index) is in focus")
} else {
print("TextField \(index) lost focus")
}
}
.padding(.vertical, 4)
}
}
struct RowViewWithButton: View {
let index: Int
@Binding var text: String
@FocusState.Binding var focusedField: Int?
var body: some View {
Button (action: {
print("RowView - button selected at index \(index)")
focusedField = index
}) {
HStack {
Text("Row \(index + 1):")
TextField("", text: $text)
.multilineTextAlignment(.leading)
.focused($focusedField, equals: index)
}
.onChange(of: focusedField) { newFocus in
if newFocus == index {
print("TextField \(index) is in focus")
} else {
print("TextField \(index) lost focus")
}
}
.foregroundColor(.primary)
}
.buttonStyle(BorderlessButtonStyle())
.padding(.vertical, 4)
}
}
#Preview {
ContentView()
.frame(width: 320, height: 250)
}
Curiosamente, quando eu testo isso no iOS, funciona bem em ambos os casos. Mas eu preciso da solução para macOS.
ATUALIZAR:
Usar onTapGesture
em vez de a Button
melhora as coisas, mas introduz um novo bug. Se eu tocar na linha inicialmente, inicialmente funciona bem, e tocar em qualquer lugar ativará o campo de texto. Mas depois de digitar algum texto e pressionar a tecla Enter (ou perder o foco de qualquer forma), se eu tentar tocar na parte da linha onde TextField
está o, ele só funciona se tocado no texto existente... não no espaço vazio na frente dele.
Adicionei .background(.red)
ao HStack e .background(.blue)
adicionei uma captura de tela para demonstrar o problema.