Введение
«Как вы сделаете нижнюю навигацию?» — вопрос, который проверяет не умение поставить библиотеку, а понимание паттерна: сколько пунктов допустимо, что говорит Material и как пункты связаны с экранами.
Нижняя навигация — это панель, по которой пользователь ходит по главным разделам приложения. На собеседовании за ней стоит проверка трёх вещей: знаете ли вы BottomNavigationView, понимаете ли правила Material про количество пунктов и умеете ли связать навигацию с экранами без сломанного бэкстека. Разберём всё по порядку.
Что такое BottomNavigationView
BottomNavigationView — стандартная нижняя панель навигации Android, реализация компонента Material Design.
Документация определяет его как панель, которая позволяет переключаться между top-level экранами в один тап, и прямо говорит: использовать её стоит, когда в приложении от трёх до пяти главных разделов. Класс наследуется от NavigationBarView — абстрактной базы нижней навигации, от которой также наследуется NavigationRailView (боковая панель).
Наполнение панели задаётся не кодом, а menu-ресурсом: у каждого пункта — title, icon и состояние enabled. Вот классический набор из трёх разделов:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/nav_home"
android:icon="@drawable/ic_home"
android:title="@string/nav_home" />
<item
android:id="@+id/nav_feed"
android:icon="@drawable/ic_feed"
android:title="@string/nav_feed" />
<item
android:id="@+id/nav_profile"
android:icon="@drawable/ic_profile"
android:title="@string/nav_profile" />
</menu><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_bottom_navigation" />
</LinearLayout>Обратите внимание: высоту панели и её вид задаёт тема Material — в коде она не нужна. wrap_content по высоте достаточно: размер контейнера определяет компонент.
Типичная ошибка на собеседовании: «Пункты добавляются через код — newTab, addItem». Это путаница с TabLayout. В BottomNavigationView пункты живут в menu-ресурсе, а код либо подписывается на выбор, либо связывает панель с навигацией. Умение объяснить роль menu — маркер, что кандидат действительно работал с компонентом.
Настройка: слушатели и связь с навигацией
Панель сделана, теперь её нужно связать с экранами — и вот здесь кандидаты начинают импровизировать.
Минимальный способ — слушатель выбора пункта. Современный вариант — setOnItemSelectedListener (в новых версиях библиотеки старый setOnNavigationItemSelectedListener помечен как deprecated):
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomNavigation = findViewById<BottomNavigationView>(R.id.bottom_navigation)
bottomNavigation.setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.nav_home -> showScreen(HomeFragment())
R.id.nav_feed -> showScreen(FeedFragment())
R.id.nav_profile -> showScreen(ProfileFragment())
}
true
}
}
}Но на собеседовании и в реальном проекте ответ уровня middle звучит иначе: через Navigation Component. Панель связывается с NavController одной строкой — setupWithNavController — и тогда пункты меню соответствуют destinations графа навигации, а бэкстек и состояния экранов настраиваются декларативно.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomNavigation = findViewById<BottomNavigationView>(R.id.bottom_navigation)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.fragment_container) as NavHostFragment
val navController = navHostFragment.navController
bottomNavigation.setupWithNavController(navController)
}
}Почему это спрашивают
setupWithNavController — короткий вопрос, который сразу делит кандидатов. Один отвечает «навешиваю listener и вручную переключаю фрагменты». Другой объясняет, что пункты меню мапятся на destinations, а бэкстеком управляет NavController, поэтому при повороте экрана и системном back навигация не ломается. Второе — это уровень middle.
Программный выбор пункта тоже задаётся через меню: menuItem.isChecked = true. И не забывайте про поведение скрытия при скролле: в CoordinatorLayout панель может исчезать при прокрутке контента через HideBottomViewOnScrollBehavior — эта фича часто всплывает в вопросах «как сделать, чтобы панель пряталась при скролле».
Правила Material и подводные камни
Material задаёт жёсткие правила для нижней навигации — и интервьюеры их спрашивают.
Спецификация прямо говорит: нижняя навигация — это от трёх до пяти пунктов, каждый пункт — top-level раздел, доступный из любого места приложения. Меньше трёх — используйте вкладки, больше пяти — вкладки или drawer. Нижнюю навигацию не смешивают с вкладками: у вкладок общая тема, у разделов нижней навигации — независимые.
Отдельный блок правил — как показывать иконки и подписи в зависимости от количества пунктов:
- Три пункта — иконки и подписи у всех.
- Четыре пункта — активный: иконка + подпись; неактивные: иконки, подписи желательны.
- Пять пунктов — активный: иконка + подпись; неактивные: иконки, подписи если помещаются.
- Иконка обязательна всегда, подпись — по правилам выше.
Частая ошибка на собеседовании: кандидат говорит «я сделаю шесть пунктов, это же просто». По спецификации Material — нет: больше пяти разделов — это уже не нижняя навигация, а повод пересмотреть структуру приложения (tabs или drawer). Интервьюер проверяет, знаете ли вы границы компонента, а не только его API.
Ещё один нюанс — Material 3. В новых проектах навигацию делают на компоненте Navigation Bar: он построен на той же базе (NavigationBarView), но выглядит иначе — выше контейнер, есть индикатор активного состояния, поддержка dynamic color и нет тени. Уметь объяснить разницу M2/M3 и то, что в Material 3 это тот же класс-основа, — приятный бонус к ответу.
Типичные ошибки на собеседовании
Вопрос про нижнюю навигацию — короткий, а ошибок на нём делают больше, чем кажется.
Первая ошибка — незнание ограничения «3–5 пунктов» и его обоснования. Вторая — путаница с TabLayout («пункты добавляются через код»). Третья — навигация вручную через supportFragmentManager без NavController, когда на вопрос «а что будет с бэкстеком при повороте» кандидат не может ответить.
Главный промах — панель без состояния. Кандидат рассказывает, как переключает фрагменты, но молчит про сохранение выбранного пункта при повороте экрана и про то, что пункты — это destinations навигационного графа. Состояние выбранного пункта хранит сам компонент, а вот согласованность с экранами — задача навигации.
Ещё одна классика: кандидат не знает, что у пункта может быть enabled=false (пункт виден, но некликабелен) и что выбор программно делается через menu.findItem(id).isChecked = true. Мелкие детали, но именно они отличают кандидата, который «читал», от того, кто «делал».
- Определение:
BottomNavigationView— панель для 3–5 top-level разделов; наследуется отNavigationBarView. - Наполнение: menu-ресурс с
id,icon,title; выбор программно —isChecked = true. - Связка: слушатель
setOnItemSelectedListenerилиsetupWithNavControllerдля корректного бэкстека. - Правила Material: 3–5 пунктов, иконка обязательна, подписи по количеству; в Material 3 — компонент Navigation Bar на той же базе.
Кто я и как помогу подготовиться
Меня зовут Рустем Бикбулатов, я senior Android-разработчик и провожу технические собеседования. Помогаю Android-разработчикам с опытом 1–2 года перейти на уровень middle за 4–8 недель: закрываю пробелы в Kotlin, Coroutines, архитектуре и тренирую ответы на собеседованиях в Яндекс, Авито и других сильных компаниях.
Вопросы про BottomNavigationView — это проверка не API, а того, как вы принимаете решения: когда панель уместна, как связать её с навигацией и какие границы задаёт Material. Более 100 учеников и разборов в моей практике показывают: именно на «простых» компонентах кандидаты с опытом 1–2 года застревают, когда дело доходит до объяснений.
Хотите, чтобы код говорил за вас на собеседовании?
Бесплатный разбор: пришлите код или резюме — посмотрю и скажу, что мешает перейти на следующий грейд.
Итоги
Итог по BottomNavigationView:
- Компонент — панель для 3–5 top-level разделов, наследуется от
NavigationBarView; пункты задаются menu-ресурсом с иконками и подписями. - Связка с экранами — слушатель
setOnItemSelectedListenerдля простых случаев илиsetupWithNavControllerдля корректного бэкстека и состояний. - Правила Material — 3–5 пунктов, иконка обязательна, отображение подписей зависит от количества; в Material 3 — компонент Navigation Bar на той же базе.
Главное, что нужно запомнить
Сильный ответ звучит так: «BottomNavigationView — панель нижней навигации для 3–5 главных разделов, пункты живут в menu-ресурсе, а связывается она с экранами через setOnItemSelectedListener или setupWithNavController; правила Material запрещают больше пяти пунктов и смешивание с вкладками». Этого достаточно, чтобы закрыть вопрос.
Если вы поняли, что на этих вопросах плаваете — не нужно перечитывать всё подряд. Напишите в Telegram, разберём вашу ситуацию и составим план подготовки под ваш уровень.