Bottomnavigationview android studio настройка

Урок 17. Android Navigation. Знакомство с BottomNavigationView. Как добавить фрагменты в панель Bottom Navigation.

На прошлом уроке мы работали с анимацией переходов между экранами. На этом уроке познакомимся с нижней панелью навигации BottomNavigationView, которая позволяет переходить между экранами – пунктами назначения навигации, а также наглядно информирует пользователя о том, на каком экране он находится. Разберемся, как добавить Bottom Navigation в андроид приложение и как добавить в BottomNavigationView новые фрагменты.

Создаем проект

С одной стороны, создать простое приложение с панелью навигации можно, не написав ни одной строчки кода. Достаточно воспользоваться готовым макетом Bottom Navigation Activity на этапе создания проекта в Android Studio. При этом создается проект приложения с нижней панелью навигации BottomNavigationView на главном экране, в которой отображается три пункта. При нажатии каждого из них меняются экраны приложения. Это все хорошо, скажете вы, но если нужно добавить или убрать экраны и пункты для них? Или добавить нижнюю навигацию в существующее приложение?

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

Неоходимые библиотеки

Если открыть файл сборки build.gradle, в секции dependencies можно увидеть подключенные библиотеки из пакета androidx.navigation (с ktx для проектов на kotlin) которые нам уже знакомы по предыдущим урокам на тему навигации в приложении. Если вы добавляете нижнюю навигацию в существующее приложение, то начинать нужно с добавления этих библиотек в ваш проект.

Граф навигации

В папке res есть папка navigation, в которой размещен все тот же граф навигации, его вы помните по предыдущим урокам. Без него, как вы понимаете, не обходится здесь и нижняя панель навигации.

Добавление экранов

Нажмите кнопку New Destination вверху и выберите Create New Destination. На экране добавления фрагментов выберите шаблон Fragment (with ViewModel). Добавьте один за другим два фрагмента – четвертый и пятый экран. Я их так и назову: FourthFragment и FifthFragment.

Вы можете выбрать при добавлении просто Fragment blank. Но связка Fragment + ViewModel предоставляет преимущества сохранения состояния экрана при изменении конфигурации – например, при повороте устройства. Подробнее об этом мы говорили в Уроке 6.

В граф навигации добавилось два фрагмента. Переименуйте их идентификаторы в соответствии с именами других пунктов назначения: navigation_fourth и navigation_fifth. Переименование всегда лучше делать через рефакторинг, нажатием комбинации Shift + F6 – это гарантирует изменение всех возможных связей.

Можно было оставить идентификаторы как было, но более правильно с точки зрения Code Convention, чтобы названия однотипных элементов были логически похожими. Да и находить их будет легче потом.

Также измените значение параметра android:label — оно используется для заголовка экрана. Впишите сюда текст, который вы хотите видеть в заголовке соответствующего экрана, желательно сохранить его затем в строковых ресурсах. Для сохранения нажмите желтую лампочку и выберите пункт «Extract string resourse», а затем придумайте название строки, которая сохранится в файле res/values/strings.xml.

На этом добавление экранов закончено. Но, если запустить приложение сейчас, они не будут отображаться, и нижняя панель навигации никак не изменится. Что ж, идем дальше.

Хост навигации

Если мы откроем папку layout, то увидим макеты всех фрагментов – пунктов назначения, и макет главного активити.

Макет activity_main.xml содержит компонент fragment – это хост навигации, в котором отображаются фрагменты – пункты назначения. Он связан с графом навигации через параметр app:navGraph.

BottomNavigationView

Также здесь присутствует и компонент BottomNavigationView. Это и есть нижняя панель навигации. Компонент BottomNavigationView является частью библиотеки компонентов материального дизайна. Эта библиотека должна быть импортирована в файле сборки модуля:

Обычно она уже есть в проекте по умолчанию.

Рассмотрим компонент BottomNavigationView боле подробно. Он содержит идентификатор nav_view, и имеет значение ширины – 0dp. Это рекомендуемое значение для всех элементов, ширина которых регулируется ограничениями, заданными корневым элементом разметки ConstraintLayout. Мы видим эти ограничения ниже, они привязывают панель к нижней части родителя, который, в свою очередь, занимает весь экран.

Высота BottomNavigationView задана по контенту, но можно установить фиксированную нужного вам размера.

Далее идут два параметра layout_marginStart и layout_marginEnd. Они регламентируют отступ слева и справа, но поскольку значения здесь равны нулю, они ни на что не влияют, и их можно удалить.

Читайте также:  Как сделать панорамный снимок андроид

Параметр android:background содержит ссылку на атрибут windowBackground и делает фон панели такой же, как фон экрана. Если вы хотите получить цвет панели, такой как на гайдлайнах сайта material.io, то замените параметр android:background=»?android:attr/windowBackground» таким:

Кстати, на сайте material.io можно найти много полезных рекомендаций как по дизайну, так и по реализации компонентов визуального интерфейса. На странице Bottom Navigation, например, указано, что рекомендованное число элементов панели нижней навигации должно быть от трех до пяти. Подписи должны быть максимально короткими и состоять, по возможности, из одного слова.

На вкладе implementation дается пример реализации нижней панели без графа навигации, а также примеры кастомизации и оформления фона и цвета пунктов нижней панели, добавления пунктам бейджей и т.д.

Добавление пунктов меню

Но вернемся к нашему проекту и компоненту BottomNavigationView в макете activity_main.xml.

Нас интересует последний параметр:

Он ссылается на файл bottom_nav_menu.xml в папке res/menu. Этот файл содержит описание пунктов меню нижней панели навигации. Следовательно, добавлять новые пункты следует здесь.

Добавим пару элементов для четвертого и пятого фрагментов. Их идентификаторы должны совпадать с идентификаторами пунктов назначения в графе навигации. Также укажите соответствующие строковые ресурсы в качестве названия пунктов в android:title.

Добаление идентификаторов в контроллер навигации

Осталось добавить идентификаторы пунктов навигации в конфигурацию контроллера навигации в классе MainActivity.

Переменная класса АppBarConfiguration содержит набор идентификаторов пунктов навигации и передается вместе с контроллером – хостом навигации – в функцию setupActionBarWithNavController. Это нужно для того, чтобы система считала каждый из пунктов назначения пунктом верхнего уровня. В противном случае каждый фрагмент будет отображать стрелку возврата назад в тулбаре слева, как это отображается на дочерних активити и фрагментах.

Попробуйте убрать какой-либо из идентификаторов пунктов назначения из набора, переданного в переменную appBarConfiguration, запустите приложение и посмотрите на экран пропущенного пункта назначения, и вы поймете, о чем речь.

Теперь, когда добавление закончено, запустите приложение. Все добавленные пункты меню должны отображаться в нижней панели навигации, и при нажатии вести на соответствующие экраны.

Рефакторинг

Теперь можно навести порядок в проекте. Дело в том, что изначально в проекте фрагменты каждого экрана со своими ViewModel расположены в отдельных папках по имени каждого пункта меню нижней панели навигации, и все это лежит в папке ui. Новые же добавленные фрагменты попали просто в главный пакет. Нужно создать в папке ui новые пакеты по имени добавленных экранов. Затем нужно перенести туда добавленные фрагменты вместе с их привязанными ViewModel. Делается это простым перетаскиванием в дереве проекта, с открытием окна рефакторинга, в котором нужно подтвердить операцию.
Теперь вы знаете, как добавить Bottom Navigation в приложение.

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

Источник

Как добавить BottomNavigationView в ваше android приложение

Рассмотрим новый компонент библиотеки поддержки материального дизайна BottomNavigationView. Это нижняя панель навигации, позволяющая переключаться между экранами приложения в одно касание, она предназначена в основном для смартфонов, поскольку расположение в нижней части экрана обеспечивает удобный и быстрый доступ для пользователя.

Этот компонент доступен в Design Support Library с версии 25.0.0 и Google рекомендует его к применению с соблюдением таких принципов дизайна:

  • Рекомендуется только для смартфонов, на планшетах и других устройствах с большим экраном лучше использовать боковое меню навигации.
  • Ширина областей значков зависит от их количества и может варьироваться от 80 до 168 dp. Высота панели — 56 dp, размер иконки 24×24 dp.
  • Панель должна содержать не меньше 3-х, но не больше 5-ти кнопок, кнопки должны помещаться на экране и не скроллиться.
  • Переключение между экранами только по тапу на кнопке, свайп не используется, что дает возможность комбинировать BottomNavigationView с вкладками. Но Google рекомендует подходить к такой комбинации с осторожностью, чтобы не дезориентировать пользователя.
  • Можно закрашивать активный значок в основной цвет приложения, либо использовать белый или черный цвета, если нижняя панель навигации цветная. Не разукрашивайте значки в разные цвета.
  • Текстовые метки должны быть максимально короткими и информативными, избегайте длинных надписей.
  • Нажатие значка на нижней панели навигации должно привести пользователя прямо к связанному со значком окну, или обновить текущее окно. Значки не должны открывать меню или всплывающие окна. Кнопка «Назад» на устройстве не должна позволять перемещаться между экранами нижней панели навигации.
  • Нижняя панель навигации может исчезать с экрана при прокрутке вверх и появляться при возвращении.

Ссылка на более подробную спецификацию есть в описании видео, а мы с вами переходим к практике — я покажу, как внедрить BottomNavigationView в приложение.

Читайте также:  Когда будет polar flow android

Для добавления поддержки нижней панели навигации в файл сборки уровня модуля нужно добавить такие зависимости:

Источник

Два года назад на Google I/O Android-разработчикам представили новое решение для навигации в приложениях — библиотеку Jetpack Navigation Component . Про маленькие приложения уже было сказано достаточно, а вот о том, с какими проблемами можно столкнуться при переводе большого приложения на Navigation Component , информации практически нет.

В этой и следующих двух статьях я расскажу о кейсах, с которыми может встретиться разработчик, желающий опробовать Navigation Component в большом Android-приложении.

UPDATE 30.12.2020:

Выводы, сделанные в этой статье, некорректны, так как при настройке BottomNavigationView была допущена серьёзная ошибка, которая повлекла за собой все описанные в статье проблемы. Подробности — в последней статье цикла.

Это текстовая версия моего выступления в рамках серии митапов по Android 11 в Android Academy. Само выступление было на английском, статью пишу на русском. Кому удобнее смотреть – велкам.

В первой статье я расскажу о кейсах, связанных с BottomNavigationView , во второй – о кейсах с вложенными графами навигации, в третьей – про навигацию в многомодульных приложениях, дип линки, встраиваемые фрагменты и диалоги. Все три статьи — лонгриды, которые, однако, способны сэкономить много времени и вам, и вашей команде.

Disclaimer

Я сделал пример, по структуре навигации повторяющий основные моменты навигации соискательского приложения hh.ru, и выхватил ряд проблем, о которых и собираюсь рассказать. Я основательно поресёрчил практическую сторону вопроса, но, разумеется, рассмотрел далеко не все возможные кейсы.

Схема моего тестового приложения выглядит так:

В цикле статей мы разберём каждый переход, который описан на этой схеме, а также несколько кейсов, которые не поместились на картинку.

Кейсы с BottomNavigationView

Когда я только-только услышал про Navigation Component , мне стало интересно: как будет работать BottomNavigationView и как Google подружит несколько отдельных back stack-ов в разных вкладках. Два года назад с этим кейсом были некоторые проблемы, и я решил проверить, как там обстоят дела сегодня.

Если кратко — проблемы не пропали, но появился способ их обойти. И, поскольку нижняя навигация сейчас есть практически в каждом большом приложении, нужно разбираться.

Первый опыт

Я установил Android Studio 4.1 Beta (последнюю более-менее стабильную версию на тот момент) и попробовал шаблон приложения с нижней навигацией. Начало было многообещающим.

  • Мне сгенерировали Activity в качестве контейнера для хоста навигации и нижней навигации

Я убрал «шумовые» атрибуты, чтобы было проще читать.

Стандартный ConstraintLayout , в который добавили BottomNavigationView и тэг для инициализации NavHostFragment -а ( Android Studio , кстати, подсвечивает, что вместо фрагмента лучше использовать FragmentContainerView ).

  • Для каждой вкладки BottomNavigationView был создан отдельный фрагмент

Все фрагменты были добавлены в качестве отдельных destination-ов в общий граф навигации.

  • А ещё в проект был добавлен файл-ресурс для описания меню BottomNavigationView

При этом я заметил, что идентификаторы элементов меню должны совпадать с идентификаторами destination-ов в графе навигации. Не самая очевидная связь между табами BottomNavigationView и фрагментами, но работаем с тем, что есть.

Пора запускать приложение

После создания приложения из шаблона я запустил его и сразу столкнулся с двумя проблемами.

Первая проблема: при переключении между вкладками их состояние не сохранялось.

Для проверки я добавил во вкладку Dashboard простенькую ViewModel со счётчиком. На гифке видно, как я переключаюсь со вкладки Home на вкладку Dashboard , увеличиваю счётчик до четырёх. После этого я переключился обратно на вкладку Home и вновь вернулся на Dashboard . Счётчик сбросился.

Баг с описанием этой проблемы уже два года висит в Issue Tracker-е. Чтобы решить её, Google-у потребовалось серьёзно переработать внутренности фреймворка Fragment -ов, чтобы поддержать возможность работать с несколькими back stack-ами одному FragmentManager -у. Недавно на Medium вышла статья Ian Lake, в которой он рассказывает, что Google серьёзно продвинулись в этом вопросе, так что, возможно, фикс проблемы с BottomNavigationView не за горами.

Вторая проблема – следствие первой. По принятым принципам навигации, когда вы нажимаете на уже выбранную вкладку BottomNavigationView, вы должны вернуться на первый фрагмент в стеке текущей вкладки. Но когда это происходит, состояние этого первого фрагмента сбрасывается, так как сам фрагмент пересоздаётся.

Для демонстрации этой проблемы я добавил на вкладку Dashboard кнопку, которая ведёт на следующий экран. На гифке видно, как я переключаюсь на вкладку Dashboard , увеличиваю счётчик до трёх, а затем перехожу на экран Graphic . Если я нажимаю на кнопку Back – то всё работает как надо, состояние вкладки не сбрасывается. Но если, находясь на экране Graphic , я ещё раз нажму на вкладку Dashboard , то после возврата на первый экран в стеке увижу, что его состояние сброшено.

Читайте также:  Начал лагать андроид что делать

«Не самое лучшее первое впечатление», – подумал я. И начал искать фикс.

У нас есть workaround

Решение этих проблем живёт в специальном репозитории Google-а с примерами работы с Architecture Components , в проекте NavigationAdvancedSample.

Большая часть фикса расположена в файле NavigationExtensions.kt. В самом проекте довольно много кода, поэтому я не буду его разбирать подробно, а вместо этого подсвечу основные моменты, которые относятся к решению проблем.

  • Во-первых, для каждой вкладки вводится отдельный, независимый граф навигации

Соответственно, для примера BottomNavigationView с тремя вкладками у нас получится три отдельных файла навигации XML, в которых в качестве startDestination будут указаны первые фрагменты вкладок.

  • Во-вторых, для каждой вкладки под капотом создаётся отдельный NavHostFragment , который будет связан с графом навигации этой вкладки

FragmentManager пока что не поддерживает работу с множеством back stack-ов одновременно, поэтому пришлось придумать альтернативное решение, которое позволило ассоциировать с каждым графом свой back stack. Им стало создание отдельного NavHostFragment -а для каждого графа. Из этого следует, что с каждой вкладкой BottomNavigationView у нас будет связан отдельный NavController .

  • В-третьих, мы устанавливаем в BottomNavigationView специальный listener , который будет заниматься переключением между back stack-ами фрагментов

В прикреплённом кусочке кода мы видим, как при переключении между вкладками BottomNavigationView выполняется специальная транзакция в FragmentManager -е, которая прикрепляет фрагмент выбранной вкладки и отцепляет все остальные фрагменты. По сути, так мы и переключаемся между различными back stack-ами.

  • В итоге метод настройки BottomNavigationView возвращает разработчику специальную LiveData , которая содержит в себе NavController выбранной вкладки. Этот NavController можно использовать, например, для обновления надписи на ActionBar -е

Метод для настройки BottomNavigationView вызывают в onCreate -е, когда Activity создаётся в первый раз, затем в методе onRestoreInstanceState , когда Activity пересоздаётся с помощью сохранённого состояния.

Кроме того, для работы фикса нужно, чтобы идентификаторы элементов меню, которое используется для инициализации табов BottomNavigationView , совпадали с идентификаторами графов навигации.

Опять же, не самая очевидная связь между этими элементами, зато работает.

После применения этого workaround-а первые две проблемы исчезли – теперь состояние вкладки сохраняется между переключениями вкладок.

Первая проблема решилась:

Адаптация workaround-а для фрагментов

Очень здорово, что workaround помог решить основную проблему с сохранением состояний, но этих фиксов мне было недостаточно. Пример из проекта NavigationAdvancedSample использовал в качестве контейнера нижней навигации Activity, мне же нужен был фрагмент.

Посмотрите внимательно на эту схему:

На ней можно увидеть, что пользователь начинает свой путь в приложении со Splash-экрана:

Google говорит, что Splash-экраны – зло, ухудшающее UX приложения. Тем не менее, Splash-экраны – суровая реальность большинства крупных Android-приложений. И если мы хотим использовать в нашем приложении Single Activity -архитектуру, то в качестве контейнера нижней навигации придётся использовать Fragment , а не Activity :

Я добавил вёрстку для фрагмента с нижней навигацией и перенёс настройку BottomNavigationView во фрагмент:

Я добавил в свой пример Splash-экран и дополнительную вкладку для BottomNavigationView . А чтобы пример стал ещё более походить на приложение для соискателей hh.ru, я также убрал из него ActionBar .

Для этого я поменял тему приложения с Theme.MaterialComponents.DayNight.DarkActionBar на Theme.MaterialComponents.DayNight.NoActionBar и убрал код для связки NavController -а с ActionBar -ом:

После всех манипуляций я включил режим Don’t keep activities, запустил свой пример и… получил краш при сворачивании приложения.

На гифке видно, как я запустил приложение, и после Splash-экрана показывается экран с нижней навигацией. После этого мы сворачиваем приложение и получаем краш.

В чём была причина? При вызове onDestroyView активный NavHostFragment пытается отвязаться от NavController -а. Так как мой фрагмент-контейнер с нижней навигацией никак не привязывал к себе NavController , который он получил из LiveData , метод Navigation.findNavController из onDestroyView крашил приложение.

Добавляем привязку NavController -а к фрагменту с нижней навигацией (для этого в Navigation Component-е есть утилитный метод Navigation.setViewNavController ), и проблема исчезает.

Но это ещё не всё. Не выключая режим Don’t keep activities, я попробовал свернуть, а затем развернуть приложение. Оно снова упало, но с другим неприятным исключением – IllegalStateException в FragmentManager – FragmentManager already executing transactions .

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

Краш происходит в методах, которые прикрепляют NavHostFragment к FragmentManager -у после их создания. Это исключение можно исправить при помощи костыля: обернуть методы attach-detach в Handler.post <> .

После добавления Handler.post приложение заработало, как надо.

Выводы по работе с BottomNavigationView

На этом с BottomNavigationView всё, на следующей неделе расскажу про кейсы с вложенными графами навигации.

Источник

Оцените статью