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

iOS15下SwiftUI键盘、NavigationView与Popover的焦点异常问题

iOS15 SwiftUI TextField焦点丢失问题修复方案

问题根因

  • iOS15对SwiftUI NavigationView的默认样式和视图重绘逻辑做了非兼容变更,iPad端默认使用分栏样式时,嵌套NavigationLink的内部视图会被频繁重建
  • 键盘弹出触发父视图布局变更时,内联在NavigationLink destination闭包中的GeometryReader会触发重绘,导致内部TextField被销毁重建,失去第一响应者身份
  • Form容器的布局重计算逻辑在iOS15中会误判输入控件的层级,导致键盘避障逻辑失效

修复步骤

1. 强制指定NavigationView为栈样式

给根视图的NavigationView添加navigationViewStyle修饰符,强制使用栈式导航,避免iPad端分栏样式的异常逻辑:

NavigationView() {
    // 原有视图内容
}
.navigationViewStyle(.stack)

2. 提取嵌套导航的目标视图为独立结构体

不要在NavigationLink的destination闭包内写内联的复杂视图,将内部的Criteria页面和Add Keyword页面分别提取为独立的View结构体,避免重绘时视图被重建。

3. 可选配置FocusState管控焦点

iOS15及以上系统可以使用@FocusState属性包装器,手动管控TextField的焦点状态,页面出现时自动激活输入框,避免焦点丢失。

修复后完整代码

import SwiftUI

// 提取独立的Criteria页面视图
struct CriteriaView: View {
    @Binding var addKeywordScreenShown: Bool
    @Binding var newKeyword: String
    
    var body: some View {
        // 如非必要可删除GeometryReader,此处保留仅做示例
        GeometryReader { gp in
            List {
                NavigationLink(destination: AddKeywordView(newKeyword: $newKeyword), isActive: $addKeywordScreenShown) {
                    Text("Add Keyword")
                        .padding(10)
                        .border(Color.primary)
                        .foregroundColor(.primary)
                }
            }
            .background(Color.gray)
            .frame(width: gp.size.width, height: gp.size.height)
        }
    }
}

// 提取独立的关键词输入页面
struct AddKeywordView: View {
    @Binding var newKeyword: String
    // iOS15+可使用FocusState强制管控焦点,可选配置
    @FocusState private var isInputFocused: Bool
    
    var body: some View {
        TextField("New Keyword", text: $newKeyword)
            .keyboardType(.alphabet)
            .focused($isInputFocused)
            .onAppear {
                // 页面出现时自动激活输入框
                isInputFocused = true
            }
    }
}

struct EditScreen: View {
    @Binding var shownBinding: Bool

    @State private var userName = ""
    @State private var newKeyword = ""
    @State private var addKeywordScreenShown = false
    @State private var criteriaScreenShown = false
    
    private var userSpecificElements: some View {
        Section(header: Text("Criteria")) {
            NavigationLink(isActive: $criteriaScreenShown, destination: {
                CriteriaView(addKeywordScreenShown: $addKeywordScreenShown, newKeyword: $newKeyword)
            }) {
                HStack() {
                    Image(systemName: "plus.circle.fill")
                    Text("Add Criteria")
                }
            }
        }
    }
    
    var body: some View {
        NavigationView() {
            Form() {
                HStack() {
                    Text("Name")
                    Spacer()
                    TextField("Enter Name", text: $userName)
                    .keyboardType(.alphabet)
                }
                HStack() {
                    Text("Avatar")
                    Spacer()
                    Button(action: {}) {
                        Image(systemName: "person")
                    }
                }
                userSpecificElements
            }
            .navigationTitle("Edit User")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button("Save") {
                        shownBinding = false
                        userName = ""
                    }
                }
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") { shownBinding = false }
                }
            }
        }
        // 强制使用栈式导航样式,修复iOS15 iPad分栏样式异常
        .navigationViewStyle(.stack)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 16:48:03