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

SwiftUI:.keyboard位置Toolbar在Tab导航及运行时显示异常解决方案

解决SwiftUI中TabView嵌套NavigationView时键盘工具栏不稳定问题

核心问题分析

当NavigationView嵌套在TabView中时,两者的生命周期交互会导致键盘工具栏的绑定关系失效:

  • Xcode真机调试时,视图层级初始化顺序异常,导致工具栏无法关联到键盘
  • 切换Tab返回时,非活跃Tab的视图被销毁重建,工具栏无法重新绑定焦点状态

有效修复方案

通过调整视图层级和明确导航样式,确保工具栏与键盘的绑定稳定:

  • 将Toolbar绑定到NavigationView的直接子视图,确保其属于NavigationView的上下文
  • 明确设置NavigationViewStyle,避免自适应样式带来的层级混乱
  • 可选:Tab切换回来时重置焦点状态,确保工具栏能正确触发

修改后的完整代码

import SwiftUI

class Settings: ObservableObject {
    static let shared = Settings()
    
    @Published var perKmFee: Double
    
    init(perKmFee: Double = 0) {
        self.perKmFee = perKmFee
    }
}

@main
struct ToolbarProblemDemoApp: App {
    var body: some Scene {
        WindowGroup {
            TabView {
                ContentView()
                    .tabItem {
                        Image(systemName: "car.fill")
                        Text("Home")
                    }
                
                SettingsView()
                    .tabItem {
                        Image(systemName: "gear")
                        Text("Settings")
                    }
            }
        }
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

struct SettingsView: View {
    enum Field: Hashable {
        case price
        case otherPrice
    }
    
    @FocusState private var focusedField: Field?
    @ObservedObject var settings = Settings.shared
    
    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    DemoTextField(value: $settings.perKmFee, title: "Price")
                        .focused($focusedField, equals: .price)
                }
            }
            // 将Toolbar绑定到NavigationView的子根视图,确保上下文关联
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        focusedField = nil
                    }
                }
            }
        }
        // 明确设置导航视图样式,避免自适应导致的层级问题
        .navigationViewStyle(.stack)
        // Tab切换回来时重置焦点,确保工具栏能正确触发
        .onAppear {
            focusedField = nil
        }
    }
}

struct DemoTextField: View {
    @Binding var value: Double
    let title: String
    private var numberFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.usesGroupingSeparator = false
        formatter.decimalSeparator = Locale.current.decimalSeparator
        formatter.alwaysShowsDecimalSeparator = false
        return formatter
    }
    
    var body: some View {
        GroupBox {
            TextField("Price", value: $value, formatter: numberFormatter)
                .keyboardType(.decimalPad)
        }
    }
}

额外说明

如果项目支持iOS 16及以上,建议用NavigationStack替代NavigationView,新的导航API在生命周期管理上更稳定,只需替换NavigationView为NavigationStack即可,无需额外调整toolbar代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:47:19