我使用的是 Android Jetpack的导航组件 附带 底部导航栏,像这样。
让我们把注意力集中在主页和Dashboard上 Dashboard会显示一个部门列表 每个部门会显示一个产品列表 每个产品会显示一个详细的描述。到目前为止,一切都能正常工作。
然而。首页应直接显示全部产品列表,这里的问题是:我怎样才能显示出的 product_list
当应用程序启动时(以及每次访问Home时),直接将片段放在Home上?
注意,我不能把 product_list
代码直接放到Home片段中,因为这样的话,Dashboard的导航就会转到Home。
另外,如果我把 findNavController().navigate(HomeFragmentDirections.nextAction())
关于 "家园 "部分 onCreateView(...)
每次我进入 "主页 "时,它都会显示产品列表,但同时也会显示 "我的产品"。涨幅 按钮,但它没有去任何地方(它去了主页,而主页又重定向至 product_list
再次)。)
我只需要 涨幅 按钮时,访问 product_list
通过Dashboard上的部门列表。该 product_list
应该显示在Home上,就好像它是Home本身一样。
所以,我在寻找一种方法来直接链接这两个片段,而不需要任何交易,或者通过避免使用 涨幅 按钮(也许是通过避免将事务添加到事务后堆栈中)。
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/bottom_nav"
app:startDestination="@+id/navigation_home">
<fragment
android:id="@+id/navigation_home"
android:name="cu.lcnicolau.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/next_action"
app:destination="@id/product_list">
<argument
android:name="departmentId"
android:defaultValue="0" />
</action>
</fragment>
<fragment
android:id="@+id/navigation_departments"
android:name="cu.lcnicolau.ui.departments.DepartmentsFragment"
android:label="@string/title_departments"
tools:layout="@layout/fragment_departments">
<action
android:id="@+id/next_action"
app:destination="@id/product_list" />
</fragment>
<fragment
android:id="@+id/product_list"
android:name="cu.lcnicolau.ui.products.ItemListFragment"
android:label="@string/title_products"
tools:layout="@layout/item_list">
<action
android:id="@+id/next_action"
app:destination="@id/product_detail" />
<argument
android:name="departmentId"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/product_detail"
android:name="cu.lcnicolau.ui.products.ItemDetailFragment"
android:label="@string/title_product_detail"
tools:layout="@layout/item_detail">
<argument
android:name="item"
app:argType="cu.lcnicolau.dummy.Product" />
</fragment>
</navigation>
这种方式或许能满足你的需求。
1. 设置 bottom_nav
创建可在导航图内任何地方使用的全局操作。DepartmentsFragment
将使用该操作导航到 ItemListFragment
.
创建动作内 navigation_home
. 这里的重要属性是 app:popUpTo="@+id/bottom_nav
(你的图形id),当其他片段调用onBackPressed时,它会从backstack中移除HomeFragment并影响到BottomNavigationView。我们将使用ActivityCallback来解决这个问题。
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/bottom_nav"
app:startDestination="@+id/navigation_home">
<action
android:id="@+id/to_product_list"
app:destination="@id/product_list" />
<fragment
android:id="@+id/navigation_home" android:name="com.example.stackoverflowhelps.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/home_to_product_list"
app:destination="@id/product_list"
app:popUpTo="@+id/bottom_nav" />
</fragment>
<fragment
android:id="@+id/product_list" android:name="com.example.stackoverflowhelps.ui.products.ProductsFragment"
android:label="@string/title_products"
tools:layout="@layout/fragment_products" >
<argument
android:name="departmentId"
app:argType="long" />
</fragment>
...
</navigation>
DepartmentsFragment
findNavController().navigate(toProductList(departementId))
HomeFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
findNavController().navigate(homeToProductList(-1))
}
2. 设置MainActivity和NavCallback
这个回调的目的是当从其他两个底部菜单中的onBackPressed时,将BottomNavigationView导航到Home。由于我们每次从Home进入ItemListFragment时,都会在backstack中丢失HomeFragment。
NavCallback.java
interface NavCallback {
enum class Nav { HOME, DASHBOARD, OFFERS }
fun navigateToMenu(nav: Nav)
}
MainActivity.java
class MainActivity : AppCompatActivity(), NavCallback {
private lateinit var navView: BottomNavigationView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// optional: if you want to permanently remove default ActionBar BackButton from ItemListFragment, add product_list navigation id to appBarConfiguration
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home,
R.id.navigation_dashboard,
R.id.navigation_offers,
R.id.product_list
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun navigateToMenu(nav: NavCallback.Nav) {
val dest: Int = when(nav) {
NavCallback.Nav.HOME -> R.id.navigation_home
NavCallback.Nav.DASHBOARD -> R.id.navigation_home
NavCallback.Nav.OFFERS -> R.id.navigation_notifications
}
navView.selectedItemId = dest
}
}
使用 NavCallback
内覆盖onBackPressed时 DepartmentsFragment
和 OffersFragment
. 我们将手动选择底部导航菜单为 "首页",请看。NavCallback.Nav.HOME
class DepartmentsFragment : Fragment() {
private var navCallback: NavCallback? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
navCallback?.navigateToMenu(NavCallback.Nav.HOME)
}
}
requireActivity().onBackPressedDispatcher.addCallback(this, callback)
}
override fun onAttach(context: Context) {
super.onAttach(context)
try {
navCallback = context as NavCallback
} catch (e: ClassCastException) {
activity.toString() + " must implements NavCallback"
}
}
override fun onDetach() {
navCallback = null
super.onDetach()
}
...
}
直到这里,我们已经得到了想要的UI流程。
3. 确定产品列表数据和后退按钮的可见性。ItemListFragment
为了方便起见,我更喜欢使用自定义工具栏视图和后退按钮。此时,我们将使用参数 departmentId
来确定后退按钮的可见性
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val departmentId: Long = arguments?.getLong("departmentId") ?: 0
if (departmentId > 0) {
textView.text = departmentId.toString()
back.visibility = View.VISIBLE
back.setOnClickListener { requireActivity().onBackPressed() }
// from fetch the data with given id
} else {
back.visibility = View.GONE
// come from HomeFragment, fetch all data
}
}