如何在Navigation Controller回退栈中跳过SearchView?
问题
调用docPageSearchView.show()打开SearchView,选择搜索结果后会打开当前查看器片段的新实例展示内容。此时按返回键会再次弹出SearchView,如何直接回到上一个查看器片段,跳过SearchView?
当前代码
Kotlin 逻辑代码
override fun onMenuItemClick(item: MenuItem): Boolean { when (item.itemId) { R.id.doc_page_search_menu_item -> binding.docPageSearchView.show() else -> return false } return true } override fun onItemClicked(model: PageEntity, position: Int, view: View) { binding.docPageSearchView.hide() navController.navigate(DocPageViewerFragmentDirections.toSelf(model.key)) }
布局代码
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.search.SearchView android:id="@+id/doc_page_search_view" android:layout_width="match_parent" android:layout_height="match_parent" android:hint="@string/hint_doc_page_search"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/search_result_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> </com.google.android.material.search.SearchView> <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="?actionBarSize" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <TextView android:id="@+id/markdown_root" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/view_indent_horizontal" android:isScrollContainer="true" android:scrollbarThumbVertical="@android:color/transparent" android:textAppearance="@style/TextAppearance.Material3.BodyLarge" android:textColor="?attr/colorOnBackground" android:textIsSelectable="true" tools:text="Lorem ipsum dolor sit amet" /> </androidx.core.widget.NestedScrollView> <com.google.android.material.bottomappbar.BottomAppBar android:id="@+id/doc_page_bottom_app_bar" style="@style/Widget.Material3.BottomAppBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:hideOnScroll="true" app:menu="@menu/menu_navigation_doc_page" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
解决方案
问题出在SearchView.show()会把自身的显示状态塞进返回栈,导致按返回键时先恢复SearchView,而不是回到上一个片段。有两种解决办法:
办法一:跳转时清理返回栈里的SearchView状态
修改onItemClicked方法,跳转新片段的时候,让导航组件清理掉当前片段之前的SearchView状态,同时手动处理返回键隐藏SearchView:
override fun onItemClicked(model: PageEntity, position: Int, view: View) { binding.docPageSearchView.hide() navController.navigate( DocPageViewerFragmentDirections.toSelf(model.key), NavOptions.Builder() // 替换成你这个查看器片段的ID,确保跳转后返回栈里只保留必要的片段 .setPopUpTo(R.id.doc_page_viewer_fragment, false) .build() ) }
然后重写片段的onBackPressed方法,当SearchView显示时直接隐藏,不让它占用返回事件:
override fun onBackPressed(): Boolean { return if (binding.docPageSearchView.isShowing) { binding.docPageSearchView.hide() true } else { super.onBackPressed() } }
办法二:禁止SearchView保存状态
Material的SearchView默认会把显示状态存进返回栈,你可以直接禁用它的状态保存:
要么在布局里加属性:
<com.google.android.material.search.SearchView android:id="@+id/doc_page_search_view" android:layout_width="match_parent" android:layout_height="match_parent" android:hint="@string/hint_doc_page_search" android:saveEnabled="false"> <!-- 加这行 -->
要么在代码里初始化时设置:
binding.docPageSearchView.isSaveEnabled = false
这样一来,SearchView的显示状态就不会进返回栈,跳转后按返回键直接回到上一个查看器片段。
内容的提问来源于stack exchange,提问作者Viewed
相关产品推荐
相关产品推荐

