具有架构导航组件的 BottomNavigation 片段的动画
Animation for BottomNavigation Fragments with Architecture Navigation Components
我已经成功地将底部导航与最新的 android 架构导航组件集成在一起。以下是我的完整代码。
- 导航
<?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/mobile_navigation"
app:startDestination="@+id/navigation_home">
<fragment
android:id="@+id/navigation_home"
android:name="in.zedone.bottomsample.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home" />
<fragment
android:id="@+id/navigation_saloons"
android:name="in.zedone.bottomsample.ui.saloons.SaloonsFragment"
android:label="@string/title_saloon"
tools:layout="@layout/fragment_saloons" />
<fragment
android:id="@+id/navigation_offers"
android:name="in.zedone.bottomsample.ui.offers.OffersFragment"
android:label="@string/title_offer"
tools:layout="@layout/fragment_offers" />
<fragment
android:id="@+id/navigation_account"
android:name="in.zedone.bottomsample.ui.account.AccountFragment"
android:label="@string/title_account"
tools:layout="@layout/fragment_account" />
</navigation>
- 底部导航视图
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:labelVisibilityMode="labeled"
app:itemTextAppearanceActive="@style/BottomNavigationView.Active"
app:itemTextAppearanceInactive="@style/BottomNavigationView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
- 主要活动
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_saloons, R.id.navigation_offers,R.id.navigation_account)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
现在如何在底部导航中的每个 tab/fragment select 上添加 transition/animation?
我对 Android 导航有点陌生,但如果您想更改默认动画,我认为这是您可以尝试的方法
将这些文件放在你的动画目录中
nav_default_enter_anim.xml
nav_default_exit_anim.xml
nav_default_pop_enter_anim.xml
nav_default_pop_exit_anim.xml
并且交易的默认动画将更改为您在上述文件中放置的动画。
它也与 BottomNavigationView 的兄弟片段一起工作(JetPack 导航组件)
// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
exitTransition = MaterialFadeThrough()
}
// FragmentB.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialFadeThrough()
}
不要使用 setupWithNavController 函数,而是按照这种方式。
首先,创建包含如下所示动画的 NavOptions。
val options = NavOptions.Builder()
.setLaunchSingleTop(true)
.setEnterAnim(R.anim.enter_from_bottom)
.setExitAnim(R.anim.exit_to_top)
.setPopEnterAnim(R.anim.enter_from_top)
.setPopExitAnim(R.anim.exit_to_bottom)
.setPopUpTo(navController.graph.startDestination, false)
.build()
然后使用 setOnNavigationItemSelectedListener 以这样的动画导航。
bottomNavigationView.setOnNavigationItemSelectedListener { item ->
when(item.itemId) {
R.id.fragmentFirst -> {
navController.navigate(R.id.fragmentFirst,null,options)
}
R.id.fragmentSecond -> {
navController.navigate(R.id.fragmentSecond,null,options)
}
R.id.fragmentThird -> {
navController.navigate(R.id.fragmentThird,null,options)
}
}
true
}
最后,你应该防止相同的项目选择情况,所以你可以添加下面的代码。
bottomNavigationView.setOnNavigationItemReselectedListener { item ->
return@setOnNavigationItemReselectedListener
我在我的项目中使用 bottomNavigation 来为页面转换添加动画。
希望对您有所帮助。
您也可以通过在每个 Fragment
中覆盖 onCreateAnimation()
并检查您是否正在进入或退出 Fragment
来保持 setupWithNavController
enter
参数,然后使用 AnimationUtils.loadAnimation(context, animationId)
.
创建适当的 Animation
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
return if (enter) {
AnimationUtils.loadAnimation(context, R.anim.fade_in)
} else {
AnimationUtils.loadAnimation(context, R.anim.fade_out)
}
}
编辑作为对 iloo 的回应:
根据 Material 设计 (https://material.io/components/bottom-navigation#behavior) 你一开始就不应该这样做,但我想它仍然可以实现。
因为当使用 setupWithNavController
所有目的地都是顶级时
永远只有一个 previousBackStackEntry
的目的地指向家
目的地,因此 previousBackStackEntry
对确定您来自哪个 Fragment
没有多大帮助。
其他方法可能是在 Activity
中有一个 public 变量,您将在其中存储
您所在的最后一个目的地,并在恢复时在每个 Fragment
中设置该变量。
您可以检查 onAnimationCreate
中的变量以了解您来自哪个 Fragment
并应用适当的动画。
我已经成功地将底部导航与最新的 android 架构导航组件集成在一起。以下是我的完整代码。
- 导航
<?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/mobile_navigation"
app:startDestination="@+id/navigation_home">
<fragment
android:id="@+id/navigation_home"
android:name="in.zedone.bottomsample.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home" />
<fragment
android:id="@+id/navigation_saloons"
android:name="in.zedone.bottomsample.ui.saloons.SaloonsFragment"
android:label="@string/title_saloon"
tools:layout="@layout/fragment_saloons" />
<fragment
android:id="@+id/navigation_offers"
android:name="in.zedone.bottomsample.ui.offers.OffersFragment"
android:label="@string/title_offer"
tools:layout="@layout/fragment_offers" />
<fragment
android:id="@+id/navigation_account"
android:name="in.zedone.bottomsample.ui.account.AccountFragment"
android:label="@string/title_account"
tools:layout="@layout/fragment_account" />
</navigation>
- 底部导航视图
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:labelVisibilityMode="labeled"
app:itemTextAppearanceActive="@style/BottomNavigationView.Active"
app:itemTextAppearanceInactive="@style/BottomNavigationView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/bottom_nav_menu" />
- 主要活动
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home, R.id.navigation_saloons, R.id.navigation_offers,R.id.navigation_account)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
现在如何在底部导航中的每个 tab/fragment select 上添加 transition/animation?
我对 Android 导航有点陌生,但如果您想更改默认动画,我认为这是您可以尝试的方法
将这些文件放在你的动画目录中
nav_default_enter_anim.xml
nav_default_exit_anim.xml
nav_default_pop_enter_anim.xml
nav_default_pop_exit_anim.xml
并且交易的默认动画将更改为您在上述文件中放置的动画。
它也与 BottomNavigationView 的兄弟片段一起工作(JetPack 导航组件)
// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
exitTransition = MaterialFadeThrough()
}
// FragmentB.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialFadeThrough()
}
不要使用 setupWithNavController 函数,而是按照这种方式。
首先,创建包含如下所示动画的 NavOptions。
val options = NavOptions.Builder()
.setLaunchSingleTop(true)
.setEnterAnim(R.anim.enter_from_bottom)
.setExitAnim(R.anim.exit_to_top)
.setPopEnterAnim(R.anim.enter_from_top)
.setPopExitAnim(R.anim.exit_to_bottom)
.setPopUpTo(navController.graph.startDestination, false)
.build()
然后使用 setOnNavigationItemSelectedListener 以这样的动画导航。
bottomNavigationView.setOnNavigationItemSelectedListener { item ->
when(item.itemId) {
R.id.fragmentFirst -> {
navController.navigate(R.id.fragmentFirst,null,options)
}
R.id.fragmentSecond -> {
navController.navigate(R.id.fragmentSecond,null,options)
}
R.id.fragmentThird -> {
navController.navigate(R.id.fragmentThird,null,options)
}
}
true
}
最后,你应该防止相同的项目选择情况,所以你可以添加下面的代码。
bottomNavigationView.setOnNavigationItemReselectedListener { item ->
return@setOnNavigationItemReselectedListener
我在我的项目中使用 bottomNavigation 来为页面转换添加动画。 希望对您有所帮助。
您也可以通过在每个 Fragment
中覆盖 onCreateAnimation()
并检查您是否正在进入或退出 Fragment
来保持 setupWithNavController
enter
参数,然后使用 AnimationUtils.loadAnimation(context, animationId)
.
Animation
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
return if (enter) {
AnimationUtils.loadAnimation(context, R.anim.fade_in)
} else {
AnimationUtils.loadAnimation(context, R.anim.fade_out)
}
}
编辑作为对 iloo 的回应:
根据 Material 设计 (https://material.io/components/bottom-navigation#behavior) 你一开始就不应该这样做,但我想它仍然可以实现。
因为当使用 setupWithNavController
所有目的地都是顶级时
永远只有一个 previousBackStackEntry
的目的地指向家
目的地,因此 previousBackStackEntry
对确定您来自哪个 Fragment
没有多大帮助。
其他方法可能是在 Activity
中有一个 public 变量,您将在其中存储
您所在的最后一个目的地,并在恢复时在每个 Fragment
中设置该变量。
您可以检查 onAnimationCreate
中的变量以了解您来自哪个 Fragment
并应用适当的动画。