iOS 15 SwiftUI中isSearching导航时自动取消的问题求助
问题
在iOS 15的SwiftUI视图中实现了搜索栏逻辑:激活搜索时显示搜索列表,未激活时显示常规内容视图。但现在遇到问题:从搜索列表触发导航链接跳转后,isSearching会自动变为false,界面切回常规内容视图。期望跳转后保持搜索状态,返回时仍能看到搜索结果,想知道如何控制isSearching的变化逻辑。
演示效果:
复现代码:
import SwiftUI struct ContentView: View { @ObservedObject var viewModel: ContentView.ViewModel var body: some View { NavigationView { VStack { ContentViewWrapper(viewModel: viewModel) } .navigationTitle("Searchable") .navigationBarTitleDisplayMode(.inline) .searchable(text: $viewModel.searchString, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search") .navigationViewStyle(.stack) .edgesIgnoringSafeArea(.top) } } } // MARK: View model for the content view extension ContentView { class ViewModel: ObservableObject { @Published var isShowingDestinationScreen = false @Published var isSearching = false @Published var searchString = "" func buttonTapped() { if !isShowingDestinationScreen { isShowingDestinationScreen = true } } func isSearchingHasChanged(newValue: Bool) { if isSearching != newValue { isSearching = newValue } } } } // MARK: Wrapper for the content view so it can be used with the searchable API struct ContentViewWrapper: View { @ObservedObject var viewModel: ContentView.ViewModel @Environment(\.isSearching) var isSearching var body: some View { VStack { if viewModel.isSearching { NavigationLink( isActive: $viewModel.isShowingDestinationScreen, destination: { DestinationView() .navigationTitle("Destination") }, label: { EmptyView() } ) SearchList() { viewModel.buttonTapped() } } else { ContentViewMenu() } } .onChange(of: isSearching) { newValue in viewModel.isSearchingHasChanged(newValue: newValue) } } } // MARK: Just three simple screens below struct ContentViewMenu: View { var body: some View { Text("Content View Menu") } } struct SearchList: View { var destinationButtonTapped: () -> Void var body: some View { VStack { Text("Search list") Button("Go to destination") { destinationButtonTapped() } } } } struct DestinationView: View { var body: some View { Text("Destination") } }
解决方案
系统默认的\.isSearching环境变量在导航跳转时会自动置为false,这是SwiftUI的内置行为。要保持搜索状态,需要自定义维护搜索激活状态,不直接依赖系统的isSearching,而是结合搜索栏的编辑回调和搜索文本状态来控制:
关键修改步骤
- 在ViewModel中添加自定义的搜索激活状态变量,替代原有的系统依赖逻辑
- 通过
searchable的onEditingChanged和onSubmit回调,手动控制自定义状态的切换 - 仅当用户主动清空搜索文本并退出搜索时,才关闭自定义搜索状态
修改后的完整代码
import SwiftUI struct ContentView: View { @ObservedObject var viewModel: ViewModel var body: some View { NavigationView { VStack { ContentViewWrapper(viewModel: viewModel) } .navigationTitle("Searchable") .navigationBarTitleDisplayMode(.inline) .searchable( text: $viewModel.searchString, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search" ) // 监听搜索栏编辑状态变化 .onEditingChanged { isEditing in if isEditing { viewModel.isSearchActive = true } else { // 仅当搜索文本为空时,才关闭搜索状态 if viewModel.searchString.isEmpty { viewModel.isSearchActive = false } } } // 处理搜索提交事件 .onSubmit(of: .search) { viewModel.isSearchActive = true } .navigationViewStyle(.stack) .edgesIgnoringSafeArea(.top) } } } extension ContentView { class ViewModel: ObservableObject { @Published var isShowingDestinationScreen = false // 自定义搜索激活状态,替代原isSearching @Published var isSearchActive = false @Published var searchString = "" func buttonTapped() { isShowingDestinationScreen = true } } } struct ContentViewWrapper: View { @ObservedObject var viewModel: ContentView.ViewModel var body: some View { VStack { // 结合自定义状态和搜索文本判断,确保状态不丢失 if viewModel.isSearchActive || !viewModel.searchString.isEmpty { NavigationLink( isActive: $viewModel.isShowingDestinationScreen, destination: { DestinationView() .navigationTitle("Destination") }, label: { EmptyView() } ) SearchList() { viewModel.buttonTapped() } } else { ContentViewMenu() } } } } struct ContentViewMenu: View { var body: some View { Text("Content View Menu") } } struct SearchList: View { var destinationButtonTapped: () -> Void var body: some View { VStack { Text("Search list") Button("Go to destination") { destinationButtonTapped() } } } } struct DestinationView: View { var body: some View { Text("Destination") } }
效果说明
- 用
isSearchActive自定义变量控制视图切换,不再受系统\.isSearching的自动重置影响 - 在
onEditingChanged中,仅当用户退出搜索且搜索文本为空时,才关闭自定义搜索状态 - 结合
searchString是否为空的判断,确保即使搜索栏失去焦点但有文本时,仍保持搜索列表显示 - 导航跳转后,自定义状态和搜索文本会被保留,返回时直接回到搜索列表界面
内容的提问来源于stack exchange,提问作者Zsolt
相关产品推荐
相关产品推荐

