Is it possible to change the transition effect from opening a fragment from a drawerlayout with the android navigation component. There is nothing in the android docs.
Sarah! Yes, it is possible. You can add your custom listener to handle navigation item selection and add animation there. I had to add one myself, for other purposes, but it definitely fits as a solution for your task.
How to:
- Add layout with drawer. Example:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<!-- Other views can be added here, or below -->
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/menu_for_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
- Find
NavigationView
by ID and assign it to a variableprivate NavigationView navigationView
in your activity, that you may extract by usingfindViewById(R.id.nav_view)
. This step is optional. You may find the view and assing naviation item selection listener without holding a reference to NavigationView; - Set navigation item selection listener:
navigationView.setNavigationItemSelectedListener(menuItem -> {
@IdRes
int id = menuItem.getItemId();
NavOptions.Builder optionsBuilder = new NavOptions.Builder();
switch (id) {
case R.id.first_menu_item_id: {
// Lets assume for the first menu item navigation is default
optionsBuilder
.setEnterAnim(R.anim.nav_default_enter_anim)
.setExitAnim(R.anim.nav_default_exit_anim)
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
.setPopExitAnim(R.anim.nav_default_pop_exit_anim);
}
break;
case R.id.second_menu_item_id: {
// Lets assume for the second menu item navigation is missing
// empty here
}
break;
case R.id.thrid_menu_item_id: {
// Lets assume for the third menu item navigation is custom
optionsBuilder
.setEnterAnim(R.anim.slide_in_right)
.setExitAnim(R.anim.slide_out_left)
.setPopEnterAnim(R.anim.slide_in_left)
.setPopExitAnim(R.anim.slide_out_right);
}
break;
}
navController.navigate(id, null, optionsBuilder.build());
// Do not forget to close the drawer
// drawer.closeDrawers();
return true;
});
This should help! Any thoughts and questions are welcome!
In case you are interested in animations mentioned in example:
slide_in_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
slide_in_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
slide_out_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
slide_out_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
Update (28 March 2020)
In case this solution doesn't work with the Drawer Menu try to use it with the following code.
Note that I placed setNavigationItemSelectedListener
call at the end of the method due to NavigationUI
functions sometimes settings it's own listener. That could also be the cause of problem.
There is a lot going on behind NavigationUI
functions and if something doesn't work right check out implementation of the functions you use.
private void setupNavigation() {
// Set custom toolbar as action bar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
// Setup navigation with toolbar and drawer
NavController navController = Navigation.findNavController(this, R.id.main_nav_host_fragment);
/* The set of destinations by id considered at the top level
of your information hierarchy. The Up button will not be displayed
when on these destinations. */
Set<Integer> set = new HashSet<>(Arrays.asList(R.id.first_fragmentId_from_nav_graph, R.id.second_fragmentId_from_nav_graph, R.id.third_fragmentId_from_nav_graph));
/* Configuration options for {@link NavigationUI} methods that interact with implementations of the
app bar pattern */
AppBarConfiguration configuration = new AppBarConfiguration.Builder(set).setDrawerLayout(drawer).build();
NavigationUI.setupWithNavController(toolbar, navController, configuration);
NavigationUI.setupWithNavController(navigationView, navController);
NavigationUI.setupActionBarWithNavController(this, navController, configuration);
// And here you set the listener.
navigationView.setNavigationItemSelectedListener(...);
}
There are multiple calls to NavigationUI
functions like setupWithNavController
and setupActionBarWithNavController
. The reason is that behind each one of them is added one more destination changed listener to navigation controller. See addOnDestinationChangedListener for more information about the listener.
- First call adds
new ToolbarOnDestinationChangedListener(toolbar, configuration)
; - Second call adds custom implementation of
NavController.OnDestinationChangedListener
that updates your navigation view in drawer correctly; - Third call adds
new ActionBarOnDestinationChangedListener(activity, configuration)
.
This configuration allows me to use a single application on a tablet with a Master-Detail pattern and on the phone as a usual application with Drawer Menu.
Referenced string resources are just:
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
But they are required for accessibility. It's very good to translate them if you support multiple languages. Basically anything used for accessibility is generally good to translate.
setNavigationItemSelectedListener
is not getting called because navigation component either doesn't know about the Drawer or the way navigation was set up is causing the issue. I will extend the answer with the configuration used in my project. –
Burnoose There is a simpler way. Internally NavigationUI
builds the NavOptions
like this:
if (navController.getCurrentDestination().getParent().findNode(item.getItemId())
instanceof ActivityNavigator.Destination) {
builder.setEnterAnim(R.anim.nav_default_enter_anim)
.setExitAnim(R.anim.nav_default_exit_anim)
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
.setPopExitAnim(R.anim.nav_default_pop_exit_anim);
} else {
builder.setEnterAnim(R.animator.nav_default_enter_anim)
.setExitAnim(R.animator.nav_default_exit_anim)
.setPopEnterAnim(R.animator.nav_default_pop_enter_anim)
.setPopExitAnim(R.animator.nav_default_pop_exit_anim);
}
You can just create these directories yourself and override the defaults. In my case I had to create the animator
folder (not anim
!) in /res/
and put 4 new animation files with these names in it. But maybe try both folders to be sure.
At the moment it works perfectly in a MaterialComponents Theme: the selected drawer item still get's highlighted and the appbar animation is still working too (unlike with some other methods).
© 2022 - 2024 — McMap. All rights reserved.