Mak*_*nia 23 android android-architecture-components
我有一个BottomNavigationView和一个应用程序ViewPager.如何使用新的"导航架构组件"实现它?
什么是最佳做法?
非常感谢
Mar*_*rat 15
BottomNavigationView使用Navigation Arch Component的默认实现对我来说没有用.单击选项卡时,它会根据导航图从头开始.
我需要在屏幕底部有5个选项卡,并为每个选项卡都有一个单独的backstack.这意味着当在标签之间切换时,您将始终返回与离开之前完全相同的状态(如在Instagram中).
我的方法如下:
ViewPager和BottomNavigationView放入activity_main.xml OnNavigationItemSelectedListener于BottomNavigationView在MainActivity.ktNavHostFragmentContainer片段的xml内部.注意:每个图表都可以相互交互.
这里重点是我们将工具栏放在活动中但不在 Container片段中.然后我们调用setupWithNavController()工具栏本身而不设置它supportActionBar.这样工具栏标题将自动更新,并自动管理后退/上移按钮.
结果:
SafeArgs并按DeepLinking预期工作.BottomNavigationManager和ViewPager(即我们可以实现OnNavigationItemReselectedListener并决定在弹出backstack之前将当前选项卡中的列表滚动到顶部).码:
activity_main.xml中
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/main_view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/main_bottom_navigation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:menu="@menu/navigation" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)
MainActivity.kt
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var viewPagerAdapter: ViewPagerAdapter
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_tab_1 -> {
main_view_pager.currentItem = 0
return@OnNavigationItemSelectedListener true
}
R.id.navigation_tab_2 -> {
main_view_pager.currentItem = 1
return@OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
main_view_pager.adapter = viewPagerAdapter
main_bottom_navigation_view.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
}
}
Run Code Online (Sandbox Code Playgroud)
ViewPagerAdapter.kt
class ViewPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> Tab1ContainerFragment()
else -> Tab2ContainerFragment()
}
}
override fun getCount(): Int {
return 2
}
}
Run Code Online (Sandbox Code Playgroud)
fragment_tab_1_container.xml
<RelativeLayout 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"
tools:context=".Tab1ContainerFragment">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tab_1_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark" />
<fragment
android:id="@+id/tab_1_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation_graph_tab_1" />
</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)
Tab1ContainerFragment.kt
class Tab1ContainerFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_tab_1_container, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val toolbar = view.findViewById<Toolbar>(R.id.tab_1_toolbar)
val navHostFragment = childFragmentManager.findFragmentById(R.id.tab_1_nav_host_fragment) as NavHostFragment? ?: return
val navController = navHostFragment.navController
val appBarConfig = AppBarConfiguration(navController.graph)
toolbar.setupWithNavController(navController, appBarConfig)
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以根据需要创建任意数量的导航图:
但是我们需要为每个标签设置一个单独的图表:
<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/navigation_graph_tab_1"
app:startDestination="@id/tab1StartFragment">
<fragment
android:id="@+id/tab1StartFragment"
android:name="com.marat.android.bottomnavigationtutorial.Tab1StartFragment"
android:label="fragment_tab_1_start"
tools:layout="@layout/fragment_tab_1_start">
<action
android:id="@+id/action_tab_1_to_content"
app:destination="@id/navigation_graph_content" />
</fragment>
<include app:graph="@navigation/navigation_graph_content" />
</navigation>
Run Code Online (Sandbox Code Playgroud)
这里,起始目标片段是您希望在选项卡中显示为第一个屏幕的任何片段.
我创建了一个在 Activity 上具有工具栏的示例,您还可以创建具有自己的工具栏的 ViewPager 片段。它OnBackPressedCallback用于后退导航,ViewModel用于设置当前片段NavController和NavHostFragment嵌套childFragmentManager片段,并使用 viewLifeCycleOwner 尊重生命周期,并在暂停时禁用回调并启用 onResume。
导航和布局架构
\n MainActivity(Appbar + Toolbar + ViewPager2 + BottomNavigationView)\n |\n |- HomeNavHostFragment\n | |- HF1 -> HF2 -> HF3\n |\n |- DashboardNavHostFragment\n | |- DF1 -> DF2 -> DF3\n |\n |- NotificationHostFragment\n |- NF1 -> NF2 -> NF3\nRun Code Online (Sandbox Code Playgroud)\n首先,为每个选项卡或片段创建一个导航图ViewPager2
nav_graph_home.xml
\n<?xml version="1.0" encoding="utf-8"?>\n<navigation xmlns:android="http://schemas.android.com/apk/res/android"\n xmlns:app="http://schemas.android.com/apk/res-auto"\n xmlns:tools="http://schemas.android.com/tools"\n android:id="@+id/nav_graph_dashboard"\n app:startDestination="@id/dashboardFragment1">\n\n\n <fragment\n android:id="@+id/dashboardFragment1"\n android:name="com.smarttoolfactory.tutorial7_1bnw_viewpager2_nestednavigation.blankfragment.DashboardFragment1"\n android:label="DashboardFragment1"\n tools:layout="@layout/fragment_dashboard1">\n <action\n android:id="@+id/action_dashboardFragment1_to_dashboardFragment2"\n app:destination="@id/dashboardFragment2" />\n </fragment>\n\n <fragment\n android:id="@+id/dashboardFragment2"\n android:name="com.smarttoolfactory.tutorial7_1bnw_viewpager2_nestednavigation.blankfragment.DashboardFragment2"\n android:label="DashboardFragment2"\n tools:layout="@layout/fragment_dashboard2">\n <action\n android:id="@+id/action_dashboardFragment2_to_dashboardFragment3"\n app:destination="@id/dashboardFragment3" />\n </fragment>\n <fragment\n android:id="@+id/dashboardFragment3"\n android:name="com.smarttoolfactory.tutorial7_1bnw_viewpager2_nestednavigation.blankfragment.DashboardFragment3"\n android:label="DashboardFragment3"\n tools:layout="@layout/fragment_dashboard3" >\n <action\n android:id="@+id/action_dashboardFragment3_to_dashboardFragment1"\n app:destination="@id/dashboardFragment1"\n app:popUpTo="@id/dashboardFragment1"\n app:popUpToInclusive="true" />\n </fragment>\n\n</navigation>\nRun Code Online (Sandbox Code Playgroud)\n其他导航图与此相同
\nBottomNavigationView 的菜单
\nmenu_bottom_nav.xml
\n<?xml version="1.0" encoding="utf-8"?>\n<menu xmlns:android="http://schemas.android.com/apk/res/android">\n\n <item\n android:id="@+id/nav_graph_home"\n android:icon="@drawable/ic_baseline_home_24"\n android:title="Home"/>\n <item\n android:id="@+id/nav_graph_dashboard"\n android:icon="@drawable/ic_baseline_dashboard_24"\n android:title="Dashboard"/>\n <item\n android:id="@+id/nav_graph_notification"\n android:icon="@drawable/ic_baseline_notifications_24"\n android:title="Notification"/>\n</menu>\nRun Code Online (Sandbox Code Playgroud)\nViewPager2 适配器
\nclass ActivityFragmentStateAdapter(fragmentActivity: FragmentActivity) :\n FragmentStateAdapter(fragmentActivity) {\n \n override fun getItemCount(): Int = 3\n\n override fun createFragment(position: Int): Fragment {\n\n return when (position) {\n 0 -> HomeNavHostFragment()\n 1 -> DashBoardNavHostFragment()\n else -> NotificationHostFragment()\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n主要活动布局
\n<?xml version="1.0" encoding="utf-8"?>\n<layout xmlns:android="http://schemas.android.com/apk/res/android"\n xmlns:app="http://schemas.android.com/apk/res-auto">\n\n <androidx.coordinatorlayout.widget.CoordinatorLayout\n android:layout_width="match_parent"\n android:layout_height="match_parent">\n\n\n <com.google.android.material.appbar.AppBarLayout\n android:id="@+id/appbar"\n android:layout_width="match_parent"\n android:layout_height="wrap_content"\n android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">\n\n <androidx.appcompat.widget.Toolbar\n android:id="@+id/toolbar"\n android:layout_width="match_parent"\n android:layout_height="?attr/actionBarSize"\n app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar" />\n\n </com.google.android.material.appbar.AppBarLayout>\n\n <androidx.constraintlayout.widget.ConstraintLayout\n android:layout_width="match_parent"\n android:layout_height="match_parent"\n app:layout_behavior="@string/appbar_scrolling_view_behavior">\n\n <androidx.viewpager2.widget.ViewPager2\n android:id="@+id/viewPager"\n android:layout_width="match_parent"\n android:layout_height="0dp"\n app:layout_constraintBottom_toBottomOf="parent"\n app:layout_constraintBottom_toTopOf="@id/bottom_nav"\n app:layout_constraintEnd_toEndOf="parent"\n app:layout_constraintStart_toStartOf="parent"\n app:layout_constraintTop_toTopOf="parent" />\n\n\n <com.google.android.material.bottomnavigation.BottomNavigationView\n android:id="@+id/bottom_nav"\n android:layout_width="match_parent"\n android:layout_height="wrap_content"\n app:layout_constraintBottom_toBottomOf="parent"\n app:menu="@menu/menu_bottom_nav" />\n\n </androidx.constraintlayout.widget.ConstraintLayout>\n\n </androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n</layout>\nRun Code Online (Sandbox Code Playgroud)\n当我们更改选项卡时,MainActivity 会监听BottomNavigationView项目的更改和当前的更改NavController,因为我们必须Appbar为每个选项卡设置导航。
class MainActivity : AppCompatActivity() {\n\n// private val appbarViewModel by viewModels<AppbarViewModel>()<AppbarViewModel>()\n\n private val appbarViewModel:AppbarViewModel by viewModels()\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n\n val dataBinding: ActivityMainBinding =\n DataBindingUtil.setContentView(this, R.layout.activity_main)\n\n val viewPager2 = dataBinding.viewPager\n val bottomNavigationView = dataBinding.bottomNav\n\n // Cancel ViewPager swipe\n viewPager2.isUserInputEnabled = false\n\n // Set viewpager adapter\n viewPager2.adapter = ActivityFragmentStateAdapter(this)\n \n // Listen bottom navigation tabs change\n bottomNavigationView.setOnNavigationItemSelectedListener {\n\n when (it.itemId) {\n R.id.nav_graph_home -> {\n viewPager2.setCurrentItem(0, false)\n return@setOnNavigationItemSelectedListener true\n\n }\n R.id.nav_graph_dashboard -> {\n viewPager2.setCurrentItem(1, false)\n return@setOnNavigationItemSelectedListener true\n }\n R.id.nav_graph_notification -> {\n viewPager2.setCurrentItem(2, false)\n return@setOnNavigationItemSelectedListener true\n }\n }\n false\n }\n\n appbarViewModel.currentNavController.observe(this, Observer { navController ->\n navController?.let {\n val appBarConfig = AppBarConfiguration(it.graph)\n dataBinding.toolbar.setupWithNavController(it, appBarConfig)\n }\n })\n\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nAppbarViewModel只有一个MutableLiveData可以设置 current NavController。使用 ViewModel 在 NavHost 片段中设置 ViewModel 并能够在 Activity 或其他片段中获取它的目的。
class AppbarViewModel : ViewModel() {\n val currentNavController = MutableLiveData<NavController?>()\n}\nRun Code Online (Sandbox Code Playgroud)\n具有 FragmentContainerView 的 NavHost 的布局,当我将 Toolbar 放入这些片段并使用时,FragmentContainerView我会收到错误,fragment如果您将 appBar 与导航一起使用,请使用。
片段_navhost_home.xml
\n<?xml version="1.0" encoding="utf-8"?>\n<layout xmlns:android="http://schemas.android.com/apk/res/android"\n xmlns:app="http://schemas.android.com/apk/res-auto">\n\n <androidx.constraintlayout.widget.ConstraintLayout\n android:layout_width="match_parent"\n android:layout_height="match_parent">\n\n <androidx.fragment.app.FragmentContainerView\n android:id="@+id/nested_nav_host_fragment_home"\n android:name="androidx.navigation.fragment.NavHostFragment"\n android:layout_width="0dp"\n android:layout_height="0dp"\n app:layout_constraintBottom_toBottomOf="parent"\n app:layout_constraintLeft_toLeftOf="parent"\n app:layout_constraintRight_toRightOf="parent"\n app:layout_constraintTop_toTopOf="parent"\n\n app:defaultNavHost="false"\n app:navGraph="@navigation/nav_graph_home"/>\n\n </androidx.constraintlayout.widget.ConstraintLayout>\n\n</layout>\nRun Code Online (Sandbox Code Playgroud)\n包含子片段和 NavController 的 NavHost Fragment,其中 3 个是相同的,所以我只放了一个
\nclass HomeNavHostFragment : BaseDataBindingFragment<FragmentNavhostHomeBinding>() {\n override fun getLayoutRes(): Int = R.layout.fragment_navhost_home\n\n private val appbarViewModel by activityViewModels<AppbarViewModel>()\n\n private var navController: NavController? = null\n\n private val nestedNavHostFragmentId = R.id.nested_nav_host_fragment_home\n\n override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n super.onViewCreated(view, savedInstanceState)\n\n val nestedNavHostFragment =\n childFragmentManager.findFragmentById(nestedNavHostFragmentId) as? NavHostFragment\n navController = nestedNavHostFragment?.navController\n\n\n // Listen on back press\n listenOnBackPressed()\n\n }\n\n private fun listenOnBackPressed() {\n requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)\n }\n\n\n override fun onResume() {\n super.onResume()\n callback.isEnabled = true\n\n // Set this navController as ViewModel\'s navController\n appbarViewModel.currentNavController.value = navController\n\n }\n\n override fun onPause() {\n super.onPause()\n callback.isEnabled = false\n }\n\n /**\n * This callback should be created with Disabled because on rotation ViewPager creates\n * NavHost fragments that are not on screen, destroys them afterwards but it might take\n * up to 5 seconds.\n *\n * ### Note: During that interval touching back button sometimes call incorrect [OnBackPressedCallback.handleOnBackPressed] instead of this one if callback is **ENABLED**\n */\n val callback = object : OnBackPressedCallback(false) {\n\n override fun handleOnBackPressed() {\n\n\n // Check if it\'s the root of nested fragments in this navhost\n if (navController?.currentDestination?.id == navController?.graph?.startDestination) {\n\n Toast.makeText(requireContext(), "AT START DESTINATION ", Toast.LENGTH_SHORT)\n .show()\n\n /*\n Disable this callback because calls OnBackPressedDispatcher\n gets invoked calls this callback gets stuck in a loop\n */\n isEnabled = false\n requireActivity().onBackPressed()\n isEnabled = true\n\n } else {\n navController?.navigateUp()\n }\n\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n嵌套导航需要注意的重要事项是
\n首先,您需要检查您是否是图表的起始目的地,因为您需要调用requireActivity().onBackPressed()回调 Activity ,否则您会卡在 HomeFragment1 处
如果您在调用之前不禁用回调,requireActivity().onBackPressed()则会陷入循环,因为 onBackPressed 也会调用 Active 回调
callback.isEnabled = false如果当前 Fragment 不可见时不禁用,则每个回调都会被调用
最后,我认为最重要的是如果你旋转你的设备
\n其他选项卡中的片段也会由 viewPager 创建,然后在 3 到 5 后销毁,但它们的 onResume 不会被调用,这会导致其他回调在创建对象时调用 handleBackPressed : OnBackPressedCallback( true ),使用
\nobject : OnBackPressedCallback(false)\nRun Code Online (Sandbox Code Playgroud)\n例如,如果回调处于活动状态,并且您在HomeFragment3打开时旋转设备,并且在回调处于活动状态时触摸后退按钮
2020-06-28 13:23:42.722 I: HomeNavHostFragment #208670033 onCreate()\n2020-06-28 13:23:42.729 I: \xe2\x8f\xb0 NotificationHostFragment #19727909 onCreate()\n2020-06-28 13:23:42.826 I: HomeNavHostFragment #208670033 onViewCreated()\n2020-06-28 13:23:42.947 I: \xe2\x8f\xb0 NotificationHostFragment #19727909 onViewCreated()\n2020-06-28 13:23:42.987 I: HomeNavHostFragment #208670033 onResume()\n2020-06-28 13:23:44.092 I: \xe2\x8f\xb0 NotificationHostFragment #19727909 handleOnBackPressed()\n2020-06-28 13:23:44.851 I: \xe2\x8f\xb0 NotificationHostFragment #19727909 handleOnBackPressed()\n2020-06-28 13:23:53.011 I: \xe2\x8f\xb0 NotificationHostFragment #19727909 onDestroyView()\n2020-06-28 13:23:53.023 I: \xe2\x8f\xb0 NotificationHostFragment #19727909 onDestroy()\nRun Code Online (Sandbox Code Playgroud)\n即使我在 HomeFragment3 可见时按后退按钮两次,\xe2\x8f\xb0 NotificationHostFragment #19727909 handleOnBackPressed()也会被调用,因为 ViewPager 创建也不可见的片段并在之后销毁它们。我的例子花了10秒,你也可以尝试一下。
编辑onBackPressedDispatcher:建议使用下面的片段,而不是在 ViewPager 2 的每个片段中,其中FragmentStateAdapter将屏幕上的活动片段设置为主要导航片段。
/**\n * FragmentStateAdapter to add ability to set primary navigation fragment\n * which lets fragment visible to be navigable when back button is pressed using\n * [FragmentStateAdapter.FragmentTransactionCallback] in [ViewPager2].\n *\n * * Create FragmentStateAdapter with viewLifeCycleOwner instead of Fragment to make sure\n * that it lives between [Fragment.onCreateView] and [Fragment.onDestroyView] while [View] is alive\n *\n * * /sf/ask/4324584351/\n */\nabstract class NavigableFragmentStateAdapter(\n fragmentManager: FragmentManager,\n lifecycle: Lifecycle\n) : FragmentStateAdapter(fragmentManager, lifecycle) {\n\n private val fragmentTransactionCallback =\n object : FragmentStateAdapter.FragmentTransactionCallback() {\n override fun onFragmentMaxLifecyclePreUpdated(\n fragment: Fragment,\n maxLifecycleState: Lifecycle.State\n ) = if (maxLifecycleState == Lifecycle.State.RESUMED) {\n\n // This fragment is becoming the active Fragment - set it to\n // the primary navigation fragment in the OnPostEventListener\n OnPostEventListener {\n fragment.parentFragmentManager.commitNow {\n setPrimaryNavigationFragment(fragment)\n }\n }\n } else {\n super.onFragmentMaxLifecyclePreUpdated(fragment, maxLifecycleState)\n }\n }\n\n init {\n // Add a FragmentTransactionCallback to handle changing\n // the primary navigation fragment\n registerFragmentTransactionCallback()\n }\n\n fun registerFragmentTransactionCallback() {\n registerFragmentTransactionCallback(fragmentTransactionCallback)\n }\n\n fun unregisterFragmentTransactionCallback() {\n unregisterFragmentTransactionCallback(fragmentTransactionCallback)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n这是完整示例的链接。您还可以将 Toolbar 放置到每个 navHost 片段中,这更简单一些。
\n您可以使用工具栏在 NavHost 片段中调用它
\nval appBarConfig = AppBarConfiguration(navController!!.graph)\ndataBinding.toolbar.setupWithNavController(navController!!, appBarConfig)\nRun Code Online (Sandbox Code Playgroud)\n
我的一个解决方案是将 ViewPager 中的片段留在导航之外,并直接在页面片段上设置操作,就好像这些页面是主机一样。为了更好地解释它:
假设您在具有 Fragment B 的 ViewPager 的 Fragment A 中,并且您尝试从 B 导航到 C
在片段 B 中,使用 ADirections 类和从 A 到 C 的操作。 findNavHost().navigateTo(ADirections.ActionFromAtoC)
小智 -2
我们可以使用底部导航组件和NavigationGraph轻松实现。
您应该为每个底部导航菜单创建相应的片段
nav_graph.xml
<?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/nav_graph"
app:startDestination="@id/actionHome">
<fragment
android:id="@+id/actionHome"
android:name="com.sample.demo.fragments.Home"
android:label="fragment_home"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/toExplore"
app:destination="@id/actionExplore" />
</fragment>
<fragment
android:id="@+id/actionExplore"
android:name="com.sample.demo.fragments.Explore"
android:label="fragment_explore"
tools:layout="@layout/fragment_explore" />
<fragment
android:id="@+id/actionBusiness"
android:name="com.sample.demo.fragments.Business"
android:label="fragment_business"
tools:layout="@layout/fragment_business" />
<fragment
android:id="@+id/actionProfile"
android:name="com.sample.demo.fragments.Profile"
android:label="fragment_profile"
tools:layout="@layout/fragment_profile" />
</navigation>
Run Code Online (Sandbox Code Playgroud)
每个导航片段 ID 和底部导航菜单项 ID 应该相同。例如这里
<fragment
android:id="@+id/actionBusiness"
android:name="com.sample.demo.fragments.Business"
android:label="fragment_business"
tools:layout="@layout/fragment_business" />
Run Code Online (Sandbox Code Playgroud)
底部导航菜单navigation.xml下方
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/actionExplore"
android:icon="@drawable/ic_search_24dp"
android:title="@string/explore" />
<item
android:id="@+id/actionBusiness"
android:icon="@drawable/ic_business_24dp"
android:title="@string/business" />
<item
android:id="@+id/actionProfile"
android:icon="@drawable/ic_profile_24dp"
android:title="@string/profile" />
</menu>
Run Code Online (Sandbox Code Playgroud)
将 nav_graph.xml 设置为 Activity_main.xml 中的 palceholder 片段
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_bg"
android:focusable="true"
android:focusableInTouchMode="true"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="@color/semi_grey"
app:itemIconTint="@drawable/bottom_bar_nav_item"
app:itemTextColor="@drawable/bottom_bar_nav_item"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/navigation" />
<include
android:id="@+id/appBarLayout"
layout="@layout/app_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<fragment
android:id="@+id/mainNavigationFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
android:paddingBottom="@dimen/activity_horizontal_margin"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="@+id/navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
app:navGraph="@navigation/nav_graph" />
</android.support.constraint.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)
将导航图映射到此处的片段app:navGraph="@navigation/nav_graph"
之后在MainActivity.java中实现导航图和bottomNavigation组件
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
NavController navController = Navigation.findNavController(this, R.id.mainNavigationFragment);
NavigationUI.setupWithNavController(navigation, navController);
Run Code Online (Sandbox Code Playgroud)
干杯!!!
| 归档时间: |
|
| 查看次数: |
5028 次 |
| 最近记录: |