SwiftUI中searchable导致返回后UI冻结问题求助
搜索框聚焦返回后UI冻结问题
问题复现代码
enum ViewRouter: Hashable, Codable { case pageOne } struct ContentView: View { @State var navStackPath = NavigationPath() var body: some View { NavigationStack(path: $navStackPath) { ZStack { Button { navStackPath.append(ViewRouter.pageOne) } label: { Text("SHOW DETAILS") } } .navigationDestination(for: ViewRouter.self) { d in switch d { case .pageOne: DetailsView() } } } } } #Preview { ContentView() } struct DetailsView: View { @State var searchString = "" var body: some View { ZStack { Text("DETAILS") } .searchable(text: $searchString) } }
问题演示

问题现象
- 点击
SHOW DETAILS按钮 - 进入详情页
- 点击搜索框唤起键盘
- 返回ContentView
- 尝试点击
SHOW DETAILS按钮,UI冻结,按钮完全失效
环境信息
- Xcode版本:15.0 beta (15A5160n)、15.0 beta 2 (15A5161b)
- 模拟器/真机:iPad模拟器(Version 15.0 (1004),SimulatorKit 633,CoreSimulator 905.2),真机也存在该问题
日志信息
UINavigationBar has changed horizontal size class without updating search bar to new placement. Fixing, but delegate searchBarPlacement callbacks have been skipped. navigationBar = <SwiftUI.UIKitNavigationBar: 0x10ad0c110; baseClass = UINavigationBar; frame = (1366 24; 1366 50); opaque = NO; autoresize = W; gestureRecognizers = <NSArray: 0x600000c717d0>; layer = <CALayer: 0x600000269d20>> delegate=0x111010000
解决方案
这是Xcode 15 beta版本中的SwiftUI已知bug,可通过以下方法规避:
方法1:用@FocusState管理搜索框焦点,页面消失时主动放弃焦点
修改DetailsView,添加焦点状态变量,在页面消失时重置焦点状态:
struct DetailsView: View { @State var searchString = "" @FocusState private var isSearchFocused: Bool var body: some View { ZStack { Text("DETAILS") } .searchable(text: $searchString) .focused($isSearchFocused) .onDisappear { isSearchFocused = false } } }
方法2:通过UIKit强制取消键盘焦点
若方法1无效,可创建UIViewRepresentable组件强制放弃第一响应者:
struct DismissKeyboardHelper: UIViewRepresentable { func makeUIView(context: Context) -> UIView { let view = UIView() view.backgroundColor = .clear return view } func updateUIView(_ uiView: UIView, context: Context) { uiView.endEditing(true) } } // 在DetailsView中调用 struct DetailsView: View { @State var searchString = "" var body: some View { ZStack { Text("DETAILS") } .searchable(text: $searchString) .onDisappear { _ = DismissKeyboardHelper() } } }
方法3:临时回退到NavigationView
若上述方法仍无效,可暂时使用旧版NavigationView替代NavigationStack(需注意iOS版本兼容性),该bug在旧导航组件中未出现:
struct ContentView: View { var body: some View { NavigationView { ZStack { NavigationLink("SHOW DETAILS", destination: DetailsView()) } } } }
优先推荐方法1,代码简洁且符合SwiftUI状态管理逻辑。待Xcode正式版发布后,该bug大概率会被官方修复。
内容的提问来源于stack exchange,提问作者zumzum
相关产品推荐
相关产品推荐

