Компонент навигации Android с переходом от Drawerlayout

Можно ли изменить эффект перехода от открытия фрагмента из drawerlayout с помощью компонента навигации Android. В документации по андроиду ничего нет.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
6
0
2 021
2

Ответы 2

Сара! Да, это возможно. Вы можете добавить свой собственный слушатель для обработки выбора элемента навигации и добавления туда анимации. Мне пришлось добавить один для других целей, но он определенно подходит для решения вашей задачи.

Как:

  1. Добавьте макет с ящиком. Пример:
<?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>
  1. Найдите NavigationView по идентификатору и назначьте его переменной private NavigationView navigationView в своей деятельности, которую вы можете извлечь с помощью findViewById(R.id.nav_view). Этот шаг не является обязательным. Вы можете найти прослушиватель выбора элемента навигации view и assing без ссылки на NavigationView;
  2. Установить прослушиватель выбора элемента навигации:
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;
       });

Это должно помочь! Приветствуются любые мысли и вопросы!


Если вас интересуют анимации, упомянутые в примере:

  • 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>

Обновление (28 марта 2020 г.)

Если это решение не работает с меню ящика, попробуйте использовать его с участием следующий код.

Обратите внимание, что я поместил вызов setNavigationItemSelectedListener в конец метода из-за функций NavigationUI, иногда настройки это собственный слушатель. Это также могло быть причиной проблемы.

За функциями NavigationUI творится много всего, и если что-то не работает, проверьте реализацию функций, которые вы используете.

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(...);
    }

Есть несколько вызовов функций NavigationUI, таких как setupWithNavController и setupActionBarWithNavController. Причина в том, что за каждым из них добавляется еще один слушатель изменения пункта назначения к контроллеру навигации. См. addOnDestinationChangedListener для получения дополнительной информации о слушателе.

  1. Первый звонок добавляет new ToolbarOnDestinationChangedListener(toolbar, configuration);
  2. Второй вызов добавляет пользовательскую реализацию NavController.OnDestinationChangedListener, которая правильно обновляет ваш вид навигации в ящике;
  3. Третий звонок добавляет new ActionBarOnDestinationChangedListener(activity, configuration).

Эта конфигурация позволяет мне использовать одно приложение на планшете с шаблоном Master-Detail и на телефоне как обычное приложение с Drawer Menu.

Ссылки на строковые ресурсы:

<string name = "navigation_drawer_open">Open navigation drawer</string>
<string name = "navigation_drawer_close">Close navigation drawer</string>

Но они необходимы для доступности. Их очень хорошо переводить, если вы поддерживаете несколько языков. В основном все, что используется для обеспечения доступности, обычно хорошо переводить.

Я попробовал вашу реализацию. Кажется, это именно то, что я ищу. У меня есть меню ящика с несколькими фрагментами, в которые я хочу добавить переход анимации. Я добавил код в свой метод onCreate в MainActivity. SetNavigationItemSelectedListener не вызывается, когда я выбираю из меню ящика.

tzg 05.03.2020 18:52

@tzg, я полагаю, что setNavigationItemSelectedListener не вызывается, потому что компонент навигации либо не знает о ящике, либо способ настройки навигации вызывает проблему. Я дополню ответ конфигурацией, используемой в моем проекте.

Jenea Vranceanu 28.03.2020 20:30

Есть способ попроще. Внутренне NavigationUI собирает NavOptions следующим образом:

    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);
    }

Вы можете просто создать эти каталоги самостоятельно и изменить значения по умолчанию. В моем случае мне пришлось создать папку animator (не anim!) В /res/ и поместить в нее 4 новых файла анимации с этими именами. Но, может быть, попробуйте обе папки, чтобы убедиться. На данный момент он отлично работает в теме MaterialComponents: выбранный элемент ящика по-прежнему выделяется, и анимация панели приложений также работает (в отличие от некоторых других методов).

Другие вопросы по теме