如何在SwiftUI中用NavigationSplitView与.searchable实现Finder风格搜索栏?
核心思路是通过布尔状态变量控制搜索栏的激活状态,配合自定义导航栏按钮与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
相关产品推荐
相关产品推荐

