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

如何在SwiftUI中用NavigationSplitView与.searchable实现Finder风格搜索栏?

实现类似Finder的折叠式搜索栏(基于NavigationSplitView + .searchable)

核心思路是通过布尔状态变量控制搜索栏的激活状态,配合自定义导航栏按钮与SwiftUI动画,实现「默认隐藏搜索框、点击图标带动画展开、图标同步隐藏」的效果。

完整代码示例

import SwiftUI

struct ContentView: View {
    // 控制搜索栏激活状态
    @State private var isSearchActive = false
    // 绑定搜索文本
    @State private var searchText = ""
    
    var body: some View {
        NavigationSplitView {
            List {
                ForEach(1...20, id: \.self) { item in
                    Text("项目 \(item)")
                }
            }
            .navigationTitle("我的文件夹")
            // 自定义导航栏右侧按钮:仅搜索未激活时显示放大镜图标
            .toolbar {
                if !isSearchActive {
                    Button(action: {
                        withAnimation {
                            isSearchActive = true
                        }
                    }) {
                        Image(systemName: "magnifyingglass")
                    }
                }
            }
            // 绑定搜索状态与文本,接管搜索栏显示逻辑
            .searchable(text: $searchText, isPresented: $isSearchActive) {
                // 可选:添加搜索建议
                Text("搜索项目").searchCompletion("搜索项目")
            }
            .navigationBarTitleDisplayMode(.inline)
        } detail: {
            Text("选择一个项目查看详情")
        }
        // 配置过渡动画,让展开/收起更自然
        .animation(.easeInOut(duration: 0.2), value: isSearchActive)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

关键实现细节

  • 状态联动:isSearchActive同时控制搜索栏的激活状态和导航栏按钮的显隐,点击图标时通过withAnimation触发状态变化,带动画过渡。
  • isPresented参数:这是实现折叠效果的核心,通过绑定该参数,替代.searchable默认的自动显示逻辑,完全由我们控制搜索栏的显示时机。
  • 工具栏按钮逻辑:仅在搜索未激活时显示放大镜图标,激活后自动隐藏,和Finder的交互逻辑完全匹配。
  • 动画优化:给整个视图添加动画配置,让搜索栏的展开/收起过渡节奏和系统自带动画一致。

额外优化方案

  • 自定义搜索栏样式:通过.searchFieldStyle()修改外观,比如使用圆角边框样式:
    .searchable(...)
    .searchFieldStyle(.roundedBorder)
    
  • 添加取消按钮:搜索激活时显示取消按钮,点击后收起搜索栏并清空文本:
    .toolbar {
        if isSearchActive {
            Button("取消") {
                withAnimation {
                    isSearchActive = false
                    searchText = ""
                }
            }
        } else {
            Button(action: {
                withAnimation {
                    isSearchActive = true
                }
            }) {
                Image(systemName: "magnifyingglass")
            }
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 13:33:26