Focused TextField 最终被 SwiftUI 中的键盘覆盖

Focused TextField ends up covered by the keyboard in SwiftUI

我想要完成的事情

用户一次在一个视图中输入值的 TextField 视图的垂直列表。在文本字段中输入值并按下键盘提交按钮后,焦点将移动到下一个文本字段。

我面临的问题

键盘挡住了活动的文本字段。我希望如果我使用 ScrollView 它会自动滚动到下一个聚焦的文本字段,但事实并非如此。

然后我决定尝试使用 ScrollViewReaderScrollViewProxy 对象滚动到焦点文本字段,这很有效!但不完全是。它滚动到选定的文本字段,但不足以越过键盘。它似乎总是在键盘顶部下方一点点(无论是否有键盘工具栏或自动更正栏或什么都没有)。

这是我调用 proxy.scrollTo(focusedInput) 后文本字段大致结束位置的屏幕截图:

这是我希望它结束​​的地方:

最小代码示例

struct ContentView: View {
    @State var inputsValues: [String]
    @FocusState var focusedInput: Int?
    
    init() {
        inputsValues = (0..<30).map { _ in "" }
    }
    
    var body: some View {
        ScrollViewReader { proxy in
            ScrollView {
                VStack {
                    ForEach((0..<inputsValues.count), id: \.self) { i in
                        TextField("Value", text: $inputsValues[i])
                            .focused($focusedInput, equals: i)
                            .submitLabel(.next)
                            .id(i)
                            .onSubmit {
                                if (i + 1) < inputsValues.count {
                                    focusedInput = i + 1
                                    proxy.scrollTo(focusedInput)
                                } else {
                                    focusedInput = nil
                                }
                            }
                    }
                }
            }
        }.toolbar {
            ToolbarItem(placement: .keyboard) {
                Text("This is toolbar")
            }
        }
    }
}

在一个闭包中改变两个以上的状态(当它们以某种方式相关或影响一个区域时)处理得不是很好(或不可靠)。解决方法是将它们分开放在不同的处理程序中。

测试 Xcode 13.3 / iOS 15.4

这是主要部分:

VStack {
   // ... other code

            .onSubmit {
                // update state here !!
                if (i + 1) < inputsValues.count {
                    focusedInput = i + 1
                } else {
                    focusedInput = nil
                }
            }
    }
}
.onChange(of: focusedInput) {
    // react on state change here !!
    proxy.scrollTo([=10=])
}

完成test module is here