如何将底部导航监听器添加到片段
How to add bottom navigation listeners to fragments
我曾经有一个包含导航主机的 activity 和允许在 3 个片段之间切换视图的 BottomNavigationView
。我最近更改了我的设计,因此最初的 activity 现在代表一个新片段,并且存在一个按钮,允许用户导航到 另一个 片段,该片段应该包含上述内容3 标签式底部导航。
我已经设法实现了初始 activity 和第一个片段。但我遇到的问题是,当我使用 3 个选项卡式底部导航栏导航到第二个片段时,我不知道如何在选项卡上实现 onClickListener
。当我在 AppCompatActivity
中设置底部导航时,它非常简单。我猜片段不应该用于这种情况。我可以轻松地使用另一个 activity class,但我想构建一个 activity 应用程序,想知道是否有其他解决方案。
在使用 activity class 的原始方法中,我能够实现如下所示的底部导航:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
setupBottomNavMenu(navController)
setupActionBar(navController)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_toolbar, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
val navigated = NavigationUI.onNavDestinationSelected(item!!, navController)
return navigated || super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(Navigation.findNavController(this, R.id.nav_host_fragment), drawer_layout)
}
private fun setupBottomNavMenu(navController: NavController) {
bottom_nav?.let {
NavigationUI.setupWithNavController(it, navController)
}
}
private fun setupActionBar(navController: NavController) {
NavigationUI.setupActionBarWithNavController(this, navController, drawer_layout)
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorMintCream"
tools:context=".activity.MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorPrimary"
android:theme="@style/ToolbarTheme"/>
<fragment
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_nav_graph"
app:defaultNavHost="true"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_navigation"/>
</LinearLayout>
</layout>
导航如下所示:
<?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" android:id="@+id/mobile_navigation.xml"
app:startDestination="@id/destination_profile">
<fragment
android:id="@+id/destination_profile"
android:name="com.example.project.profile.ProfileFragment"
android:label="Profile" />
<fragment
android:id="@+id/destination_achievements"
android:name="com.example.project.fragments.AchievementsFragment"
android:label="Achievements" />
<fragment
android:id="@+id/destination_logs"
android:name="com.example.project.fragments.LogsFragment"
android:label="Logs" />
<fragment
android:id="@+id/destination_settings"
android:name="com.example.project.fragments.SettingsFragment"
android:label="Settings" />
</navigation>
最后是菜单:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/destination_profile"
android:icon="@drawable/ic_person_black_24dp"
android:title="@string/profile"/>
<item
android:id="@+id/destination_logs"
android:icon="@drawable/ic_fitness_center_black_24dp"
android:title="@string/logs"/>
<item
android:id="@+id/destination_achievements"
android:icon="@drawable/ic_star_black_24dp"
android:title="@string/achievements"/>
</menu>
同样,我尝试将其应用于如下片段:
class MainFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
var binding: FragmentMainBinding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_main,
container,
false
)
val application = requireNotNull(this.activity).application
val dataSource = UserProfileDatabase.getInstance(application).userProfileDao
val viewModelFactory = MainViewModelFactory(dataSource, application)
val navController = this.findNavController()
NavigationUI.setupWithNavController(binding.bottomNav, navController)
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_toolbar, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val navController = this.findNavController()
val navigated = NavigationUI.onNavDestinationSelected(item, navController)
return navigated || super.onOptionsItemSelected(item)
}
companion object {
fun newInstance(): MainFragment = MainFragment()
}
}
xml 与 activity 几乎完全相同。
我希望在单击选项卡元素时调用 onOptionsItemSelected()
,但我无法这样做。如何在这些选项卡元素上实现侦听器,以便导航到正确的片段目的地?
为什么不保留 BottomNavigationView
的第一个实现,这很好,并使用 addOnDestinationChangedListener
.
将其与新实现结合起来
按住按钮的 FirstFragment
将隐藏 BottomNavigationView
,而带有 3 个选项卡式底部导航的 SecondFragment
将显示它。
例如:
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.id == R.id.first_fragment) {
// your intro fragment will hide your bottomNavigationView
bottomNavigationView.visibility = View.GONE
} else if (destination.id == R.id.second_fragment){
// your second fragment will show your bottomNavigationView
bottomNavigationView.visibility = View.VISIBLE
}
}
通过这种方式,您可以将控制权放在 Activity 而不是 Fragment 中,这样可以更好地与您的听众和您的 NavController
.
互动
保持菜单项的 ID 与图形 ID 相同,只需使用 1 行代码即
val navHostFragment =childFragmentManager.findFragmentById(R.id.fragmentContainerView) 作为 NavHostFragment
val navController = navHostFragment.navController
binding.bottomNavBar.setupWithNavController(navController)
我曾经有一个包含导航主机的 activity 和允许在 3 个片段之间切换视图的 BottomNavigationView
。我最近更改了我的设计,因此最初的 activity 现在代表一个新片段,并且存在一个按钮,允许用户导航到 另一个 片段,该片段应该包含上述内容3 标签式底部导航。
我已经设法实现了初始 activity 和第一个片段。但我遇到的问题是,当我使用 3 个选项卡式底部导航栏导航到第二个片段时,我不知道如何在选项卡上实现 onClickListener
。当我在 AppCompatActivity
中设置底部导航时,它非常简单。我猜片段不应该用于这种情况。我可以轻松地使用另一个 activity class,但我想构建一个 activity 应用程序,想知道是否有其他解决方案。
在使用 activity class 的原始方法中,我能够实现如下所示的底部导航:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
setupBottomNavMenu(navController)
setupActionBar(navController)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_toolbar, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
val navigated = NavigationUI.onNavDestinationSelected(item!!, navController)
return navigated || super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(Navigation.findNavController(this, R.id.nav_host_fragment), drawer_layout)
}
private fun setupBottomNavMenu(navController: NavController) {
bottom_nav?.let {
NavigationUI.setupWithNavController(it, navController)
}
}
private fun setupActionBar(navController: NavController) {
NavigationUI.setupActionBarWithNavController(this, navController, drawer_layout)
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorMintCream"
tools:context=".activity.MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorPrimary"
android:theme="@style/ToolbarTheme"/>
<fragment
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_nav_graph"
app:defaultNavHost="true"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_navigation"/>
</LinearLayout>
</layout>
导航如下所示:
<?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" android:id="@+id/mobile_navigation.xml"
app:startDestination="@id/destination_profile">
<fragment
android:id="@+id/destination_profile"
android:name="com.example.project.profile.ProfileFragment"
android:label="Profile" />
<fragment
android:id="@+id/destination_achievements"
android:name="com.example.project.fragments.AchievementsFragment"
android:label="Achievements" />
<fragment
android:id="@+id/destination_logs"
android:name="com.example.project.fragments.LogsFragment"
android:label="Logs" />
<fragment
android:id="@+id/destination_settings"
android:name="com.example.project.fragments.SettingsFragment"
android:label="Settings" />
</navigation>
最后是菜单:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/destination_profile"
android:icon="@drawable/ic_person_black_24dp"
android:title="@string/profile"/>
<item
android:id="@+id/destination_logs"
android:icon="@drawable/ic_fitness_center_black_24dp"
android:title="@string/logs"/>
<item
android:id="@+id/destination_achievements"
android:icon="@drawable/ic_star_black_24dp"
android:title="@string/achievements"/>
</menu>
同样,我尝试将其应用于如下片段:
class MainFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
var binding: FragmentMainBinding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_main,
container,
false
)
val application = requireNotNull(this.activity).application
val dataSource = UserProfileDatabase.getInstance(application).userProfileDao
val viewModelFactory = MainViewModelFactory(dataSource, application)
val navController = this.findNavController()
NavigationUI.setupWithNavController(binding.bottomNav, navController)
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_toolbar, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val navController = this.findNavController()
val navigated = NavigationUI.onNavDestinationSelected(item, navController)
return navigated || super.onOptionsItemSelected(item)
}
companion object {
fun newInstance(): MainFragment = MainFragment()
}
}
xml 与 activity 几乎完全相同。
我希望在单击选项卡元素时调用 onOptionsItemSelected()
,但我无法这样做。如何在这些选项卡元素上实现侦听器,以便导航到正确的片段目的地?
为什么不保留 BottomNavigationView
的第一个实现,这很好,并使用 addOnDestinationChangedListener
.
按住按钮的 FirstFragment
将隐藏 BottomNavigationView
,而带有 3 个选项卡式底部导航的 SecondFragment
将显示它。
例如:
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.id == R.id.first_fragment) {
// your intro fragment will hide your bottomNavigationView
bottomNavigationView.visibility = View.GONE
} else if (destination.id == R.id.second_fragment){
// your second fragment will show your bottomNavigationView
bottomNavigationView.visibility = View.VISIBLE
}
}
通过这种方式,您可以将控制权放在 Activity 而不是 Fragment 中,这样可以更好地与您的听众和您的 NavController
.
保持菜单项的 ID 与图形 ID 相同,只需使用 1 行代码即 val navHostFragment =childFragmentManager.findFragmentById(R.id.fragmentContainerView) 作为 NavHostFragment
val navController = navHostFragment.navController
binding.bottomNavBar.setupWithNavController(navController)