You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI的Keyboard Toolbar作用域问题及多文本框独立工具栏实现方法

问题结论

这个现象属于SwiftUI的预期行为。toolbar修饰符的作用域是它所属的整个视图层级,而非绑定到添加修饰符的单个输入控件上。只要当前激活的输入控件处于toolbar所在的视图层级范围内,定义的键盘工具栏就会自动显示,这就是你给第一个TextField加的工具栏会在第二个TextField激活时也出现的原因。

实现独立键盘工具栏的方案

有两种常用的实现方式:

方案1:通过FocusState跟踪聚焦状态动态渲染

使用@FocusState记录当前激活的输入框,在全局toolbar中根据聚焦状态切换不同的工具栏内容:

struct ContentView: View {
    @State private var first = ""
    @State private var second = ""
    // 跟踪当前聚焦的输入框
    @FocusState private var focusedField: Field?
    
    enum Field: Hashable {
        case first, second
    }
    
    var body: some View {
        VStack {
            TextField("First", text: $first)
                .focused($focusedField, equals: .first)
            
            TextField("Second", text: $second)
                .focused($focusedField, equals: .second)
        }
        .toolbar {
            ToolbarItem(placement: .keyboard) {
                // 根据当前聚焦的字段显示不同工具栏
                switch focusedField {
                case .first:
                    Button("Test") { }
                case .second:
                    Button("另一个按钮") { }
                case nil:
                    EmptyView()
                }
            }
        }
    }
}

方案2:拆分视图隔离toolbar作用域

将每个TextField和对应的toolbar封装到独立的子视图中,利用子视图的作用域隔离实现工具栏独立:

struct ContentView: View {
    @State private var first = ""
    @State private var second = ""
    
    var body: some View {
        VStack {
            FirstTextField(text: $first)
            SecondTextField(text: $second)
        }
    }
}

// 第一个输入框独立子视图
struct FirstTextField: View {
    @Binding var text: String
    @FocusState private var isFocused: Bool
    
    var body: some View {
        TextField("First", text: $text)
            .focused($isFocused)
            .toolbar {
                // 仅当前子视图内的输入框激活时显示
                ToolbarItem(placement: .keyboard) {
                    Button("Test") { }
                }
            }
    }
}

// 第二个输入框独立子视图
struct SecondTextField: View {
    @Binding var text: String
    @FocusState private var isFocused: Bool
    
    var body: some View {
        TextField("Second", text: $text)
            .focused($isFocused)
            .toolbar {
                ToolbarItem(placement: .keyboard) {
                    Button("SecondAction") { }
                }
            }
    }
}

内容的提问来源于stack exchange,提问作者Marcus Rossel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 11:09:04