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

SwiftUI中TabView切换后其他视图FocusState键盘Done按钮不显示

SwiftUI TabView子视图键盘Done按钮不显示问题

问题详情

开发了一个包含三个子视图的TabView页面,聚焦第一个视图的TextField时,键盘上方正常显示Done按钮;但切换到第二、第三个视图后,聚焦其内部TextField时,键盘上方没有出现Done按钮。每个视图都单独设置了@FocusState属性,但问题仍未解决。

原代码示例

import SwiftUI

struct TabViewTest: View {
    var body: some View {
        TabView {
            
            ViewOne()
                .tabItem {
                    Image(systemName: "1.circle")
                }
            
            ViewTwo()
                .tabItem {
                    Image(systemName: "2.circle")
                }
            
            ViewThree()
                .tabItem {
                    Image(systemName: "3.circle")

                }
        }
    }
}

#Preview {
    TabViewTest()
}

import SwiftUI

struct ViewOne: View {
    
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    var body: some View {
        NavigationStack {
            VStack {
                Text("Text 1")
                TextField("Text 1", text: $text)
                    .focused($isFocused)
                    
                
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = false
                    }
                }
            }
        }
    }
}

#Preview {
    ViewOne()
}

import SwiftUI

struct ViewTwo: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    var body: some View {
        NavigationStack {
            VStack {
                Text("Text 2")
                TextField("Text 2", text: $text)
                    .focused($isFocused)
                    
                
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = false
                    }
                }
            }
        }
    }
}


#Preview {
    ViewTwo()
}

问题原因

这是SwiftUI中TabView与NavigationStack嵌套的常见问题:TabView默认会延迟加载非当前选中的子视图,当切换到第二/第三个视图时,其内部独立的NavigationStack没有正确关联到当前窗口的场景上下文,导致键盘工具栏无法被系统正确渲染。

解决方案

方案1:将NavigationStack提升到TabView外层(推荐)

把所有子视图的NavigationStack移到TabView外面,让整个TabView共享一个全局导航栈,这样键盘工具栏能稳定绑定到正确的上下文。

修改后代码:

import SwiftUI

struct TabViewTest: View {
    var body: some View {
        // 全局NavigationStack包裹TabView
        NavigationStack {
            TabView {
                ViewOne()
                    .tabItem {
                        Image(systemName: "1.circle")
                    }
                
                ViewTwo()
                    .tabItem {
                        Image(systemName: "2.circle")
                    }
                
                ViewThree()
                    .tabItem {
                        Image(systemName: "3.circle")
                    }
            }
        }
    }
}

// 子视图移除内部的NavigationStack
struct ViewOne: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack {
            Text("Text 1")
            TextField("Text 1", text: $text)
                .focused($isFocused)
        }
        .toolbar {
            ToolbarItemGroup(placement: .keyboard) {
                Spacer()
                Button("Done") {
                    isFocused = false
                }
            }
        }
    }
}

struct ViewTwo: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack {
            Text("Text 2")
            TextField("Text 2", text: $text)
                .focused($isFocused)
        }
        .toolbar {
            ToolbarItemGroup(placement: .keyboard) {
                Spacer()
                Button("Done") {
                    isFocused = false
                }
            }
        }
    }
}

struct ViewThree: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack {
            Text("Text 3")
            TextField("Text 3", text: $text)
                .focused($isFocused)
        }
        .toolbar {
            ToolbarItemGroup(placement: .keyboard) {
                Spacer()
                Button("Done") {
                    isFocused = false
                }
            }
        }
    }
}

#Preview {
    TabViewTest()
}

方案2:强制子视图切换时重建(不推荐,影响性能)

如果必须保留每个子视图的独立NavigationStack,可以通过绑定TabView的选中状态,给子视图添加.id()强制切换时重建视图,确保NavigationStack重新关联上下文。

修改后代码:

import SwiftUI

struct TabViewTest: View {
    // 绑定Tab选中状态
    @State private var selectedTab = 0
    
    var body: some View {
        TabView(selection: $selectedTab) {
            ViewOne()
                .tabItem {
                    Image(systemName: "1.circle")
                }
                .tag(0)
            
            ViewTwo()
                .tabItem {
                    Image(systemName: "2.circle")
                }
                .tag(1)
                // 用选中状态作为id,切换时强制重建视图
                .id(selectedTab)
            
            ViewThree()
                .tabItem {
                    Image(systemName: "3.circle")
                }
                .tag(2)
                .id(selectedTab)
        }
    }
}

// 子视图保留原有结构不变
struct ViewOne: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    var body: some View {
        NavigationStack {
            VStack {
                Text("Text 1")
                TextField("Text 1", text: $text)
                    .focused($isFocused)
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = false
                    }
                }
            }
        }
    }
}

struct ViewTwo: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    var body: some View {
        NavigationStack {
            VStack {
                Text("Text 2")
                TextField("Text 2", text: $text)
                    .focused($isFocused)
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = false
                    }
                }
            }
        }
    }
}

struct ViewThree: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    var body: some View {
        NavigationStack {
            VStack {
                Text("Text 3")
                TextField("Text 3", text: $text)
                    .focused($isFocused)
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = false
                    }
                }
            }
        }
    }
}

注意:方案2会导致Tab切换时子视图完全重建,可能丢失临时状态,且影响性能,仅在无法调整NavigationStack结构时使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 13:32:45