1b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake/* 2b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * Copyright (C) 2017 The Android Open Source Project 3b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 4b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * Licensed under the Apache License, Version 2.0 (the "License"); 5b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * you may not use this file except in compliance with the License. 6b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * You may obtain a copy of the License at 7b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 8b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * http://www.apache.org/licenses/LICENSE-2.0 9b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 10b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * Unless required by applicable law or agreed to in writing, software 11b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * distributed under the License is distributed on an "AS IS" BASIS, 12b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * See the License for the specific language governing permissions and 14b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * limitations under the License. 15b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 16b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 179187ef81d7c051c5e829e8589182d93828ca4a19Ian Lakepackage androidx.navigation.ui; 18b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 19b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.animation.ObjectAnimator; 20b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.animation.ValueAnimator; 21b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lakeimport android.support.annotation.IdRes; 22b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.annotation.NonNull; 239187ef81d7c051c5e829e8589182d93828ca4a19Ian Lakeimport android.support.annotation.Nullable; 24b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.design.widget.BottomNavigationView; 25b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.design.widget.NavigationView; 26b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.v4.view.GravityCompat; 27b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.v4.widget.DrawerLayout; 28b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.v7.app.ActionBar; 29b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.v7.app.ActionBarDrawerToggle; 30b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.v7.app.AppCompatActivity; 31b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.support.v7.graphics.drawable.DrawerArrowDrawable; 32b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.text.TextUtils; 33b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.view.Menu; 34b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.view.MenuItem; 35b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lakeimport android.view.ViewParent; 36b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 371503d52153986fdcfe7e744795010708b7410892Ian Lakeimport androidx.navigation.NavController; 381503d52153986fdcfe7e744795010708b7410892Ian Lakeimport androidx.navigation.NavDestination; 39b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lakeimport androidx.navigation.NavGraph; 401503d52153986fdcfe7e744795010708b7410892Ian Lakeimport androidx.navigation.NavOptions; 411503d52153986fdcfe7e744795010708b7410892Ian Lake 42b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake/** 43b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * Class which hooks up elements typically in the 'chrome' of your application such as global 44b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * navigation patterns like a navigation drawer or bottom nav bar with your {@link NavController}. 45b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 4655565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lakepublic class NavigationUI { 47b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 48b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake // No instances. Static utilities only. 4955565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake private NavigationUI() { 50b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 51b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 52b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake /** 53b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * Attempt to navigate to the {@link NavDestination} associated with the given MenuItem. This 54b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * MenuItem should have been added via one of the helper methods in this class. 55b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 56ad7324a8dee986a702d6455158c1d7014243f4b1Ian Lake * <p>Importantly, it assumes the {@link MenuItem#getItemId() menu item id} matches a valid 57ad7324a8dee986a702d6455158c1d7014243f4b1Ian Lake * {@link NavDestination#getAction(int) action id} or 58b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * {@link NavDestination#getId() destination id} to be navigated to.</p> 59b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 60b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * @param item The selected MenuItem. 6155565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * @param navController The NavController that hosts the destination. 62b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * @return True if the {@link NavController} was able to navigate to the destination 63b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * associated with the given MenuItem. 64b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 6555565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake public static boolean onNavDestinationSelected(@NonNull MenuItem item, 6655565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @NonNull NavController navController) { 673b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets return onNavDestinationSelected(item, navController, false); 683b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets } 693b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets 703b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets private static boolean onNavDestinationSelected(@NonNull MenuItem item, 713b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets @NonNull NavController navController, boolean popUp) { 723b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets NavOptions.Builder builder = new NavOptions.Builder() 733b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets .setLaunchSingleTop(true) 743b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets .setEnterAnim(R.anim.nav_default_enter_anim) 753b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets .setExitAnim(R.anim.nav_default_exit_anim) 763b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets .setPopEnterAnim(R.anim.nav_default_pop_enter_anim) 773b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets .setPopExitAnim(R.anim.nav_default_pop_exit_anim); 783b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets if (popUp) { 79b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake builder.setPopUpTo(findStartDestination(navController.getGraph()).getId(), false); 803b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets } 813b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets NavOptions options = builder.build(); 82b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake try { 833b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets //TODO provide proper API instead of using Exceptions as Control-Flow. 843b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets navController.navigate(item.getItemId(), null, options); 85b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake return true; 86b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } catch (IllegalArgumentException e) { 87b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake return false; 88b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 89b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 90b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 91b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake /** 92e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * Handles the Up button by delegating its behavior to the given NavController. This should 93e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * generally be called from {@link AppCompatActivity#onSupportNavigateUp()}. 9455565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * <p>If you do not have a {@link DrawerLayout}, you should call 9555565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * {@link NavController#navigateUp()} directly. 96e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * 97e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * @param drawerLayout The DrawerLayout that should be opened if you are on the topmost level 98e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * of the app. 9955565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * @param navController The NavController that hosts your content. 100e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * @return True if the {@link NavController} was able to navigate up. 101e4870a3767a88a0644ababb597f87e99bc77648eIan Lake */ 10255565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake public static boolean navigateUp(@Nullable DrawerLayout drawerLayout, 10355565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @NonNull NavController navController) { 104b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake if (drawerLayout != null && navController.getCurrentDestination() 105b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake == findStartDestination(navController.getGraph())) { 106e4870a3767a88a0644ababb597f87e99bc77648eIan Lake drawerLayout.openDrawer(GravityCompat.START); 107e4870a3767a88a0644ababb597f87e99bc77648eIan Lake return true; 108e4870a3767a88a0644ababb597f87e99bc77648eIan Lake } else { 109e4870a3767a88a0644ababb597f87e99bc77648eIan Lake return navController.navigateUp(); 110e4870a3767a88a0644ababb597f87e99bc77648eIan Lake } 111e4870a3767a88a0644ababb597f87e99bc77648eIan Lake } 112e4870a3767a88a0644ababb597f87e99bc77648eIan Lake 113e4870a3767a88a0644ababb597f87e99bc77648eIan Lake /** 114b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * Sets up the ActionBar returned by {@link AppCompatActivity#getSupportActionBar()} for use 115b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * with a {@link NavController}. 116b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 117b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * <p>By calling this method, the title in the action bar will automatically be updated when 118b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}). 119b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 120b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * <p>The action bar will also display the Up button when you are on a non-root destination. 12155565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * Call {@link #navigateUp(DrawerLayout, NavController)} to handle the Up button. 122b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 123b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * @param activity The activity hosting the action bar that should be kept in sync with changes 124b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * to the NavController. 12555565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * @param navController The NavController that supplies the secondary menu. Navigation actions 12655565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * on this NavController will be reflected in the title of the action bar. 127b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 12855565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake public static void setupActionBarWithNavController(@NonNull AppCompatActivity activity, 12955565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @NonNull NavController navController) { 13055565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake setupActionBarWithNavController(activity, navController, null); 131b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 132b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 133b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake /** 134b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * Sets up the ActionBar returned by {@link AppCompatActivity#getSupportActionBar()} for use 135b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * with a {@link NavController}. 136b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 137b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * <p>By calling this method, the title in the action bar will automatically be updated when 138b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}). 139b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 140b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * <p>The action bar will also display the Up button when you are on a non-root destination and 141b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * the drawer icon when on the root destination, automatically animating between them. 14255565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * Call {@link #navigateUp(DrawerLayout, NavController)} to handle the Up button. 14355565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * @param activity The activity hosting the action bar that should be kept in sync with changes 14455565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * to the NavController. 145e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * @param navController The NavController whose navigation actions will be reflected 146e4870a3767a88a0644ababb597f87e99bc77648eIan Lake * in the title of the action bar. 147b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * @param drawerLayout The DrawerLayout that should be toggled from the home button 148b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 14955565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake public static void setupActionBarWithNavController(@NonNull AppCompatActivity activity, 15055565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @NonNull NavController navController, 15155565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @Nullable DrawerLayout drawerLayout) { 1520730cdb7a158e81e3ff5212bbcf964f4b8e7b03bIan Lake navController.addOnNavigatedListener( 1530730cdb7a158e81e3ff5212bbcf964f4b8e7b03bIan Lake new ActionBarOnNavigatedListener(activity, drawerLayout)); 154b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 155b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 156b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake /** 157cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake * Sets up a {@link NavigationView} for use with a {@link NavController}. This will call 15855565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * {@link #onNavDestinationSelected(MenuItem, NavController)} when a menu item is selected. 159cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake * The selected item in the NavigationView will automatically be updated when the destination 160cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake * changes. 161b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 162b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * @param navigationView The NavigationView that should be kept in sync with changes to the 163b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * NavController. 16455565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * @param navController The NavController that supplies the primary and secondary menu. 16555565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * Navigation actions on this NavController will be reflected in the 16655565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * selected item in the NavigationView. 167b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 16855565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake public static void setupWithNavController(@NonNull final NavigationView navigationView, 16955565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @NonNull final NavController navController) { 170cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake navigationView.setNavigationItemSelectedListener( 171cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake new NavigationView.OnNavigationItemSelectedListener() { 172b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake @Override 173cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake public boolean onNavigationItemSelected(@NonNull MenuItem item) { 1743b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets boolean handled = onNavDestinationSelected(item, navController, true); 175b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake if (handled) { 176b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake ViewParent parent = navigationView.getParent(); 177b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake if (parent instanceof DrawerLayout) { 178b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake ((DrawerLayout) parent).closeDrawer(navigationView); 179b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 180b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 181e4870a3767a88a0644ababb597f87e99bc77648eIan Lake return handled; 182b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 183b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake }); 184b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake navController.addOnNavigatedListener(new NavController.OnNavigatedListener() { 185b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake @Override 1869187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake public void onNavigated(@NonNull NavController controller, 1879187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake @NonNull NavDestination destination) { 188b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake Menu menu = navigationView.getMenu(); 189b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake for (int h = 0, size = menu.size(); h < size; h++) { 190b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake MenuItem item = menu.getItem(h); 191b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake item.setChecked(matchDestination(destination, item.getItemId())); 192b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 193b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 194b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake }); 195b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 196b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 197b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake /** 198cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake * Sets up a {@link BottomNavigationView} for use with a {@link NavController}. This will call 19955565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * {@link #onNavDestinationSelected(MenuItem, NavController)} when a menu item is selected. The 200cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake * selected item in the BottomNavigationView will automatically be updated when the destination 201cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake * changes. 202b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * 203b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * @param bottomNavigationView The BottomNavigationView that should be kept in sync with 204b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * changes to the NavController. 20555565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * @param navController The NavController that supplies the primary menu. 20655565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * Navigation actions on this NavController will be reflected in the 20755565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake * selected item in the BottomNavigationView. 208b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 20955565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake public static void setupWithNavController( 21055565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @NonNull final BottomNavigationView bottomNavigationView, 21155565dc7a0172c95ab6a0d9ceaec0752ef54b940Ian Lake @NonNull final NavController navController) { 212cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake bottomNavigationView.setOnNavigationItemSelectedListener( 213cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake new BottomNavigationView.OnNavigationItemSelectedListener() { 214cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake @Override 215cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake public boolean onNavigationItemSelected(@NonNull MenuItem item) { 2163b2023c498cd9dfe14244bc1b7f0ac673d039f4bSergey Vasilinets return onNavDestinationSelected(item, navController, true); 217cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake } 218cdeea78c311ec40b2e870d8de8275c25de9e5be4Ian Lake }); 219b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake navController.addOnNavigatedListener(new NavController.OnNavigatedListener() { 220b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake @Override 2219187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake public void onNavigated(@NonNull NavController controller, 2229187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake @NonNull NavDestination destination) { 223b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake Menu menu = bottomNavigationView.getMenu(); 224b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake for (int h = 0, size = menu.size(); h < size; h++) { 225b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake MenuItem item = menu.getItem(h); 226b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake if (matchDestination(destination, item.getItemId())) { 227b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake item.setChecked(true); 228b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 229b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 230b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 231b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake }); 232b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 233b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 234b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake /** 235b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake * Determines whether the given <code>destId</code> matches the NavDestination. This handles 236b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake * both the default case (the destination's id matches the given id) and the nested case where 237b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake * the given id is a parent/grandparent/etc of the destination. 238b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake */ 239b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake private static boolean matchDestination(@NonNull NavDestination destination, 240b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake @IdRes int destId) { 241b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake NavDestination currentDestination = destination; 242b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake while (currentDestination.getId() != destId && currentDestination.getParent() != null) { 243b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake currentDestination = currentDestination.getParent(); 244b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake } 245b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake return currentDestination.getId() == destId; 246b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake } 247b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake 248b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake /** 249b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake * Finds the actual start destination of the graph, handling cases where the graph's starting 250b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake * destination is itself a NavGraph. 251b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake */ 252b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake private static NavDestination findStartDestination(@NonNull NavGraph graph) { 253b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake NavDestination startDestination = graph; 254b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake while (startDestination instanceof NavGraph) { 255b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake NavGraph parent = (NavGraph) startDestination; 256b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake startDestination = parent.findNode(parent.getStartDestination()); 257b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake } 258b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake return startDestination; 259b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake } 260b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake 261b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake /** 262b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * The OnNavigatedListener specifically for keeping the ActionBar updated. This handles both 263b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake * updating the title and updating the Up Indicator transitioning between the 264b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake */ 265b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake private static class ActionBarOnNavigatedListener implements NavController.OnNavigatedListener { 266b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake private final AppCompatActivity mActivity; 2679187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake @Nullable 268b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake private final DrawerLayout mDrawerLayout; 269b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake private DrawerArrowDrawable mArrowDrawable; 270b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake private ValueAnimator mAnimator; 271b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 272b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake ActionBarOnNavigatedListener( 2739187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake @NonNull AppCompatActivity activity, @Nullable DrawerLayout drawerLayout) { 274b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake mActivity = activity; 275b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake mDrawerLayout = drawerLayout; 276b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 277b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 278b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake @Override 2799187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake public void onNavigated(@NonNull NavController controller, 2809187ef81d7c051c5e829e8589182d93828ca4a19Ian Lake @NonNull NavDestination destination) { 281b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake ActionBar actionBar = mActivity.getSupportActionBar(); 282b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake CharSequence title = destination.getLabel(); 283b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake if (!TextUtils.isEmpty(title)) { 284b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake actionBar.setTitle(title); 285b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 286b0cd4b0bbd6ec1aa3958afc7f3be74d949ff3a1eIan Lake boolean isStartDestination = findStartDestination(controller.getGraph()) == destination; 287b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake actionBar.setDisplayHomeAsUpEnabled(mDrawerLayout != null || !isStartDestination); 2880730cdb7a158e81e3ff5212bbcf964f4b8e7b03bIan Lake setActionBarUpIndicator(mDrawerLayout != null && isStartDestination); 289b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 290b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake 2910730cdb7a158e81e3ff5212bbcf964f4b8e7b03bIan Lake void setActionBarUpIndicator(boolean showAsDrawerIndicator) { 292b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake ActionBarDrawerToggle.Delegate delegate = mActivity.getDrawerToggleDelegate(); 2930730cdb7a158e81e3ff5212bbcf964f4b8e7b03bIan Lake boolean animate = true; 294b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake if (mArrowDrawable == null) { 295b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake mArrowDrawable = new DrawerArrowDrawable( 296b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake delegate.getActionBarThemedContext()); 297b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake delegate.setActionBarUpIndicator(mArrowDrawable, 0); 2980730cdb7a158e81e3ff5212bbcf964f4b8e7b03bIan Lake // We're setting the initial state, so skip the animation 2990730cdb7a158e81e3ff5212bbcf964f4b8e7b03bIan Lake animate = false; 300b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 301b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake float endValue = showAsDrawerIndicator ? 0f : 1f; 302b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake if (animate) { 303b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake float startValue = mArrowDrawable.getProgress(); 304b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake if (mAnimator != null) { 305b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake mAnimator.cancel(); 306b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 307b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake mAnimator = ObjectAnimator.ofFloat(mArrowDrawable, "progress", 308b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake startValue, endValue); 309b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake mAnimator.start(); 310b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } else { 311b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake mArrowDrawable.setProgress(endValue); 312b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 313b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 314b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake } 315b6e6df6f03047d67829ee5e99e7b9c31886f863fIan Lake} 316