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
相关产品推荐
相关产品推荐

