聚焦空.searchable()修饰符返回视图引发Navigation无响应Bug
问题分析与解决方案
这并非操作不当导致,是SwiftUI在iOS 16 + NavigationStack(或设置.stack样式的NavigationView)组合下的已知Bug:当空内容的.searchable()处于聚焦状态时,调用环境变量dismiss返回主视图,会残留一个不可见的空白UIView,完全遮挡主视图的交互操作。
Bug触发条件
- 使用
NavigationStack(iOS 16+)或设置.navigationViewStyle(.stack)的NavigationView - 搜索栏处于聚焦状态且输入内容为空
- 通过
@Environment(\.dismiss)返回上一级视图
解决方案
核心思路是在调用dismiss前先让搜索栏失去焦点,以下几种方式均可解决该问题:
方案1:主动取消所有第一响应者
在dismiss前调用系统方法取消当前的第一响应者(即聚焦的搜索栏):
Button("Go back") { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) dismiss() }
方案2:绑定搜索栏聚焦状态并主动取消
通过@FocusState绑定搜索栏的聚焦状态,在返回前手动设置为false:
struct DetailView: View { @Environment(\.dismiss) private var dismiss @State private var searchText = "" @FocusState private var isSearchFocused: Bool // 新增聚焦状态 var body: some View { VStack { Text("Detail view") Button("Go back") { isSearchFocused = false // 先取消搜索栏聚焦 dismiss() } } .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always)) .focused($isSearchFocused) // 绑定聚焦状态到搜索栏 } }
方案3:重置搜索文本并延迟返回
通过清空搜索文本触发搜索栏状态变化,再延迟执行dismiss确保焦点已移除:
Button("Go back") { searchText = "" DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { dismiss() } }
以上方案均能避免残留遮挡视图的问题,同时满足使用NavigationStack的需求。
内容的提问来源于stack exchange,提问作者Kevin D
相关产品推荐
相关产品推荐

