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

iOS 18 Beta中SwiftUI导航栏UISearchBar不显示问题求助

iOS 18 Beta 中导航栏UISearchBar不显示的解决思路

问题背景

在iOS 17及更早版本正常运行的代码,到iOS 18 Beta中出现导航栏.principal位置的UISearchBar(通过UIViewRepresentable封装)无法显示的问题,添加额外ToolbarItem能临时显示,但返回后又消失。这是iOS 18对Toolbar布局逻辑和UIKit视图兼容性调整导致的。

解决方法

方案1:改用SwiftUI原生组件替代UIKit封装

优先用SwiftUI原生组件实现搜索栏,彻底规避UIKit与SwiftUI的兼容性问题,在iOS18上表现稳定:

struct NextView: View {
    var number: Int
    @State private var text = ""
    @FocusState private var isSearchFocused: Bool

    var body: some View {
        Text("\(number)")
            .toolbar {
                ToolbarItem(placement: .principal) {
                    // 模拟UISearchBar样式的原生TextField
                    HStack(spacing: 8) {
                        Image(systemName: "magnifyingglass")
                            .foregroundColor(.secondary)
                        TextField("Search", text: $text)
                            .focused($isSearchFocused)
                            .textFieldStyle(.plain)
                    }
                    .padding(.horizontal, 12)
                    .padding(.vertical, 6)
                    .background(Color(.systemGray5))
                    .cornerRadius(8)
                }
                // 可选:添加取消按钮,和原生搜索栏行为一致
                ToolbarItem(placement: .topBarTrailing) {
                    if isSearchFocused {
                        Button("Cancel") {
                            isSearchFocused = false
                            text = ""
                        }
                    }
                }
            }
            .onAppear {
                // 可选:页面出现时自动聚焦搜索框
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                    isSearchFocused = true
                }
            }
    }
}

方案2:修复UIViewRepresentable的实现错误

原代码中直接在struct里声明let searchBar = UISearchBar()是值类型的错误用法,会导致实例复用异常,修改成在makeUIView内创建实例,并完善updateUIView逻辑:

struct SearchBar: UIViewRepresentable {
    @Binding var searchText: String
    var onSubmit: (() -> Void)?

    func makeUIView(context: Context) -> UISearchBar {
        let searchBar = UISearchBar() // 在这里创建实例,避免值类型复用问题
        searchBar.placeholder = "Search"
        searchBar.text = searchText
        searchBar.delegate = context.coordinator
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: Context) {
        // 同步文本变化,之前的updateUIView是空的,补上这个逻辑
        if uiView.text != searchText {
            uiView.text = searchText
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UISearchBarDelegate {
        let parent: SearchBar

        init(_ parent: SearchBar) {
            self.parent = parent
        }

        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            parent.searchText = searchText
        }

        func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
            searchBar.resignFirstResponder()
            parent.onSubmit?()
        }
    }
}

修改后NextView的Toolbar代码保持原样即可,iOS18下能正常显示且返回后不会消失。

方案3:强制Toolbar重新渲染(临时 workaround)

如果不想修改组件实现,可以通过重置Toolbar的id强制刷新,解决返回后消失的问题:

struct NextView: View {
    var number: Int
    @State private var text = ""
    @State private var toolbarId = UUID()

    var body: some View {
        Text("\(number)")
            .toolbar(id: toolbarId) {
                ToolbarItem(placement: .principal) {
                    SearchBar(searchText: $text)
                }
            }
            .onAppear {
                // 页面出现时重置id,强制Toolbar重新加载
                toolbarId = UUID()
            }
    }
}

这个方法属于临时 workaround,适合快速验证,但推荐优先用前两个方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 01:41:00