Sheet视图中SwiftUI键盘Toolbar不显示的问题及修复需求
问题:Sheet中嵌入的视图无法显示键盘Toolbar
单独展示ManualDeviceCodeInput视图时,绑定在数字键盘上的Toolbar能正常显示;但将该视图通过.sheet modifier嵌入弹窗后,Toolbar完全不出现。需求是为第一个仅接受N/O字符的输入框,在数字键盘上方添加快捷按钮Toolbar,希望Toolbar能显示在键盘与Sheet底部之间。
解决方案
在Sheet环境中,键盘Toolbar必须附加到Sheet的根视图层级才能被正确渲染,不能仅绑定在单个TextField上。同时需要确保Toolbar的条件逻辑能正确响应焦点状态,以下是修改后的实现:
修改后的完整代码
import SwiftUI import Combine struct CharInputModifier: ViewModifier { @Binding var char: String var textLimit = 1 func limitText(_ upper: Int) { if char.count > upper { char = String(char.prefix(upper)) } } func body(content: Content) -> some View { content .multilineTextAlignment(.center) .keyboardType(.numberPad) .onReceive(Just(char)) { _ in limitText(textLimit) } .font(.largeTitle) .frame(height: 100) .background(Color(.graySecondary).opacity(0.6)) .cornerRadius(20) .overlay( RoundedRectangle(cornerRadius: 20) .stroke(.gray, lineWidth: 1) .opacity(0.5) ) } } struct ManualDeviceCodeInput: View { enum FieldFocus { case fieldOne, fieldTwo, fieldThree, fieldFour, fieldFive } @FocusState private var fieldFocusState: FieldFocus? @State var fieldOne: String = "" @State var fieldTwo: String = "" @State var fieldThree: String = "" @State var fieldFour: String = "" @State var fieldFive: String = "" var body: some View { VStack { HStack(spacing: 15) { TextField("", text: $fieldOne) .modifier(CharInputModifier(char: $fieldOne)) .onChange(of: fieldOne) { newVal in if !"NO".contains(newVal) { fieldOne = "" } else if newVal.count == 1 { fieldFocusState = .fieldTwo } } .focused($fieldFocusState, equals: .fieldOne) TextField("", text: $fieldTwo) .modifier(CharInputModifier(char: $fieldTwo)) .onChange(of: fieldTwo) { newVal in if newVal.count == 1 { fieldFocusState = .fieldThree } else if newVal.count == 0 { fieldFocusState = .fieldOne } } .focused($fieldFocusState, equals: .fieldTwo) TextField("", text: $fieldThree) .modifier(CharInputModifier(char: $fieldThree)) .onChange(of: fieldThree) { newVal in if newVal.count == 1 { fieldFocusState = .fieldFour } else if newVal.count == 0 { fieldFocusState = .fieldTwo } } .focused($fieldFocusState, equals: .fieldThree) TextField("", text: $fieldFour) .modifier(CharInputModifier(char: $fieldFour)) .onChange(of: fieldFour) { newVal in if newVal.count == 1 { fieldFocusState = .fieldFive } else if newVal.count == 0 { fieldFocusState = .fieldThree } } .focused($fieldFocusState, equals: .fieldFour) TextField("", text: $fieldFive) .modifier(CharInputModifier(char: $fieldFive)) .onChange(of: fieldFive) { newVal in if newVal.count == 0 { fieldFocusState = .fieldFour } } .focused($fieldFocusState, equals: .fieldFive) } } // 将Toolbar附加到视图根层级,Sheet环境下才能正确渲染 .toolbar { ToolbarItem(placement: .keyboard) { if fieldFocusState == .fieldOne { HStack(spacing: 20) { Button(action: { fieldOne = "N" }) { Text("N") .font(.headline) .foregroundStyle(.white) } Divider() Button(action: { fieldOne = "O" }) { Text("O") .font(.headline) .foregroundStyle(.white) } } .padding() .background(Color.blue) .cornerRadius(10) } else { // 其他输入框聚焦时可以留空或添加其他内容 Spacer() } } } } } // 示例:如何在Sheet中调用该视图 struct ContentView: View { @State private var showSheet = false var body: some View { Button("打开输入弹窗") { showSheet = true } .sheet(isPresented: $showSheet) { ManualDeviceCodeInput() .padding() } } }
关键修改说明
- Toolbar层级调整:将
.toolbar从单个TextField移到ManualDeviceCodeInput的根VStack上,确保Sheet环境能识别到Toolbar配置。 - 条件渲染优化:调整Toolbar内的判断逻辑,确保只有当第一个输入框聚焦时才显示N/O按钮组,其他情况可以添加占位或留空。
- 视觉优化:给Toolbar按钮组添加背景色,避免在Sheet中与键盘背景融合,提升辨识度。
内容的提问来源于stack exchange,提问作者jonasmylesx
相关产品推荐
相关产品推荐

