如何在 SwiftUI 中管理子视图中的焦点?

问题描述 投票:0回答:1

问题

大家好

我有一个父视图,其中包含多个子视图,其中包含多个文本字段。

我想向键盘工具栏添加 V 形以轻松将焦点移动到下一个 TextField,但我不知道如何访问子视图的 FocusState。

是否有办法获取与焦点标识符对应的视图(?,不知道该怎么称呼它)?

家长视图

struct ParentView: View {
    
    @FocusState var focusedChild: Int?
    
    var body: some View {
        ForEach(1..<5) { index in
            ChildView(index: index)
                .focused($focusedChild, equals: index)
        }
        .toolbar {
            
            ToolbarItemGroup(placement: .keyboard) {
                Button {
                    // focusPrevious()                  <--
                    // Is there a way to access the view associated with the index or the current focusedChild?
                    // ChildView[index].focusState = ChildView[index].focusState + 1 % 3
                } label: {
                    Image(systemName: "chevron.left")
                }

                Button {
                    //
                } label: {
                    Image(systemName: "chevron.right")
                }
                
                Spacer()
                
                Button {
                    focusedChild = nil
                } label: {
                    Image(systemName: "keyboard.chevron.compact.down")
                }
                
            }
        }
    }
}

子视图

struct ChildView: View {
    
    var index: Int
    
    @State var field1: String = ""
    @State var field2: String = ""
    @State var field3: String = ""
    
    @FocusState var focusedField: Int?
    
    var body: some View {
        VStack {
            Text(String(index))
            TextField("Field 1", text: $field1)
                .focused($focusedField, equals: 1)
            TextField("Field 2", text: $field2)
                .focused($focusedField, equals: 2)
            TextField("Field 3", text: $field3)
                .focused($focusedField, equals: 3)
        }
    }
}

我尝试过的事情

我尝试将工具栏添加到 ChildView,但这会导致每个 childView 都有一对 V 形图案(在本例中为 3 对 V 形图案),而不是只有一对。

任何帮助将不胜感激,谢谢!

swiftui focus subview
1个回答
0
投票

由于子视图已经采用了

index
,因此只需根据它分配不同的焦点状态即可。如果您以连续数字的方式执行此操作,“转到下一个/上一个文本字段”将是微不足道的。您可以将它们指定为
index * 3
index * 3 + 1
index * 3 + 2

子视图不应在每个子视图中具有

FocusState
,而应采用
FocusState<Int?>.Binding
(与常规
Binding
类似,但用于焦点状态)。

struct ChildView: View {
    
    let index: Int
    
    @State var field1: String = ""
    @State var field2: String = ""
    @State var field3: String = ""
    
    let focusedField: FocusState<Int?>.Binding
    
    var body: some View {
        VStack {
            Text(String(index))
            TextField("Field 1", text: $field1)
                .focused(focusedField, equals: index * 3)
            TextField("Field 2", text: $field2)
                .focused(focusedField, equals: index * 3 + 1)
            TextField("Field 3", text: $field3)
                .focused(focusedField, equals: index * 3 + 2)
        }
    }
}

为了更灵活的方法,

ChildView
可以只获取所有三个文本字段的焦点状态,例如

let textField1Focus: Int
let textField2Focus: Int
let textField3Focus: Int

无论如何,现在您应该删除

.focused
s 上的
ChildView
修饰符:

ForEach(0..<4) { index in
    ChildView(index: index, focusedField: $focusedChild)
}

那么前进和后退按钮就是:

Button {
    if let focusedChild, focusedChild > 0 {
        // be careful here, self.focusedChild and focusedChild are not the same thing!
        // focusedChild is the unwrapped value!
        self.focusedChild? -= 1
    }
} label: {
    Image(systemName: "chevron.left")
}

Button {
    if let focusedChild, focusedChild < 11 {
        self.focusedChild? += 1
    }
} label: {
    Image(systemName: "chevron.right")
}
© www.soinside.com 2019 - 2024. All rights reserved.