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

SwiftUI中不使用系统NavigationView为List添加搜索栏的方案

完全可以实现,不需要依赖系统内置NavigationView/NavigationStack的搜索能力,手动搭建搜索栏+数据过滤逻辑即可,和你已有的自定义导航栏可以无缝适配。

具体实现步骤
  • 自定义独立搜索栏组件
    搜索栏本身就是普通的SwiftUI视图组合,不需要依附任何系统导航容器,核心是通过@Binding对外暴露搜索输入状态,内置输入框、搜索图标、清除按钮、取消按钮基础交互即可,示例代码:

    import SwiftUI
    
    struct CustomSearchBar: View {
        @Binding var searchText: String
        @State private var isEditing = false
        
        var body: some View {
            HStack(spacing: 8) {
                Image(systemName: "magnifyingglass")
                    .foregroundColor(.secondary)
                
                TextField("输入关键词搜索", text: $searchText)
                    .padding(7)
                    .padding(.horizontal, 24)
                    .background(Color(.systemGray6))
                    .cornerRadius(8)
                    .overlay(
                        HStack {
                            Spacer()
                            if isEditing, !searchText.isEmpty {
                                Button {
                                    searchText = ""
                                } label: {
                                    Image(systemName: "xmark.circle.fill")
                                        .foregroundColor(.secondary)
                                        .padding(.trailing, 8)
                                }
                            }
                        }
                    )
                    .onTapGesture {
                        withAnimation { isEditing = true }
                    }
                
                if isEditing {
                    Button("取消") {
                        withAnimation {
                            isEditing = false
                            searchText = ""
                            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
                        }
                    }
                    .foregroundColor(.accentColor)
                    .transition(.move(edge: .trailing))
                }
            }
            .padding(.horizontal, 16)
        }
    }
    
  • 整合自定义导航栏、搜索栏与List组件
    将自定义搜索栏放在你已完成的自定义导航栏下方(或导航栏内部,根据你的设计需求调整位置),在业务视图中维护搜索关键词状态,基于关键词对列表原始数据做过滤,将过滤后的数据传给List渲染即可。

    注意:系统提供的.searchable()修饰符必须依附系统导航容器才能生效,脱离NavigationView/NavigationStack使用不会展示任何搜索UI,不要用这个修饰符。

    整合示例代码:

    struct ListPage: View {
        // 原始列表数据源
        @State private var originList = ["SwiftUI", "UIKit", "Objective-C", "Flutter", "React Native", "HarmonyOS"]
        // 搜索关键词状态
        @State private var searchText = ""
        
        // 过滤后的展示数据
        var displayList: [String] {
            let keyword = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
            guard !keyword.isEmpty else { return originList }
            return originList.filter { $0.localizedCaseInsensitiveContains(keyword) }
        }
        
        var body: some View {
            VStack(spacing: 0) {
                // 你已经搭建完成的自定义导航栏
                CustomNavigationBar(title: "内容列表")
                // 新增的自定义搜索栏
                CustomSearchBar(searchText: $searchText)
                    .padding(.vertical, 8)
                // 列表组件,直接使用过滤后的数据
                List(displayList, id: \.self) { item in
                    Text(item)
                        .padding(.vertical, 4)
                }
                .listStyle(.plain)
            }
        }
    }
    
  • 可选扩展优化

    • 滚动收起键盘:iOS16及以上系统可以直接给List加.scrollDismissesKeyboard(.immediately)修饰符,低版本可以给List加滑动手势监听,滑动时主动调用收起键盘的方法即可
    • 输入防抖:如果列表数据量较大、或者搜索逻辑需要触发网络请求,可以引入Combine框架对搜索输入做防抖处理,避免频繁触发过滤/请求逻辑,核心代码:
      import Combine
      // 在业务视图中添加持有订阅的集合
      @State private var cancellableSet = Set<AnyCancellable>()
      
      // 在视图的onAppear修饰符中绑定防抖逻辑
      .onAppear {
          $searchText
              .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
              .sink { keyword in
                  // 这里可以执行搜索请求、重排数据等逻辑
              }
              .store(in: &cancellableSet)
      }
      
    • 样式适配:搜索栏的颜色、圆角、边距、图标都可以根据你App的设计规范自由调整,不会出现系统搜索栏和自定义导航栏风格不统一的问题。

内容的提问来源于stack exchange,提问作者Mc.Lover

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 09:51:25