Панель навигации

Последнее обновление: 17.04.2024

Для управления навигацией мы можем использовать стандартные встроенные компоненты типа кнопок, определять свои компоненты, однако специально для целей навигации Compose также предоставляет специальный компонент - NavigationBar, который представляет навигационную панель. Каждый отдельный элемент этой панели представляет компонент NavigationBarItem.

Реализация NavigationBar обычно включает содержит цикл forEach, который проходит по списку и для каждого его элемента создает отдельный компонент BNavigationBarItem. Для NavigationBarItem настраивается иконку и текст, а также обработчик onClick для перехода к соответствующему пункту назначения.

Рассмотрим небольшой примерчик:

package com.example.helloapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Face
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController


class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Main()
        }
    }
}
@Composable
fun Main() {
    val navController = rememberNavController()
    Column(Modifier.padding(8.dp)) {
        NavHost(navController, startDestination = NavRoutes.Home.route, modifier = Modifier.weight(1f)) {
            composable(NavRoutes.Home.route) { Home() }
            composable(NavRoutes.Contacts.route) { Contacts()  }
            composable(NavRoutes.About.route) { About() }
        }
        BottomNavigationBar(navController = navController)
    }
}

@Composable
fun BottomNavigationBar(navController: NavController) {
    NavigationBar {
        val backStackEntry by navController.currentBackStackEntryAsState()
        val currentRoute = backStackEntry?.destination?.route

        NavBarItems.BarItems.forEach { navItem ->
            NavigationBarItem(
                selected = currentRoute == navItem.route,
                onClick = {
                    navController.navigate(navItem.route) {
                        popUpTo(navController.graph.findStartDestination().id) {saveState = true}
                        launchSingleTop = true
                        restoreState = true
                    }
                },
                icon = {
                    Icon(imageVector = navItem.image,
                        contentDescription = navItem.title)
                },
                label = {
                    Text(text = navItem.title)
                }
            )
        }
    }
}

object NavBarItems {
    val BarItems = listOf(
        BarItem(
            title = "Home",
            image = Icons.Filled.Home,
            route = "home"
        ),
        BarItem(
            title = "Contacts",
            image = Icons.Filled.Face,
            route = "contacts"
        ),
        BarItem(
            title = "About",
            image = Icons.Filled.Info,
            route = "about"
        )
    )
}

data class BarItem(
    val title: String,
    val image: ImageVector,
    val route: String
)

@Composable
fun Home(){
    Text("Home Page", fontSize = 30.sp)
}
@Composable
fun Contacts(){
    Text("Contact Page", fontSize = 30.sp)
}
@Composable
fun About(){
    Text("About Page", fontSize = 30.sp)
}

sealed class NavRoutes(val route: String) {
    object Home : NavRoutes("home")
    object Contacts : NavRoutes("contacts")
    object About : NavRoutes("about")
}

Рассмотрим основные моменты. Прежде всего для представления отдельного элемента панели навигации определяем класс BarItem:

data class BarItem(
    val title: String,
    val image: ImageVector,
    val route: String
)

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

Для представления набора ссылок навигации определяем объект NavBarItems, который содержит список из трех навигационных ссылок:

object NavBarItems {
    val BarItems = listOf(
        BarItem(
            title = "Home",
            image = Icons.Filled.Home,
            route = "home"
        ),
        BarItem(
            title = "Contacts",
            image = Icons.Filled.Face,
            route = "contacts"
        ),
        BarItem(
            title = "About",
            image = Icons.Filled.Info,
            route = "about"
        )
    )
}

Для создания самой навигационной панели определяем компонент BottomNavigationBar:

@Composable
fun BottomNavigationBar(navController: NavController) {
    NavigationBar {
        val backStackEntry by navController.currentBackStackEntryAsState()
        val currentRoute = backStackEntry?.destination?.route

        NavBarItems.BarItems.forEach { navItem ->
            NavigationBarItem(
                selected = currentRoute == navItem.route,
                onClick = {
                    navController.navigate(navItem.route) {
                        popUpTo(navController.graph.findStartDestination().id) {saveState = true}
                        launchSingleTop = true
                        restoreState = true
                    }
                },
                icon = {
                    Icon(imageVector = navItem.image,
                        contentDescription = navItem.title)
                },
                label = {
                    Text(text = navItem.title)
                }
            )
        }
    }
}

Фактически этот компонент является оберткой над NavigationBar, в который передает объект NavController для выполнения навигации.

Внутри BottomNavigationBar мы можем идентифицировать текущий маршрут с помощью метода currentBackStackEntryAsState() контроллера навигации. Это позволит провести некоторую стилизацию элементов панели на основе текущего маршрута:

val backStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = backStackEntry?.destination?.route

Далее проходим по всем элементам в списке и выводим каждый элемент с помощью компонента NavigationBarItem:

NavBarItems.BarItems.forEach { navItem ->
    NavigationBarItem(
        selected = currentRoute == navItem.route,
        onClick = {
            navController.navigate(navItem.route) {
                popUpTo(navController.graph.findStartDestination().id) {saveState = true}
                launchSingleTop = true
                restoreState = true
            }
        },
        icon = {
            Icon(imageVector = navItem.image,
            contentDescription = navItem.title)
        },
        label = {
            Text(text = navItem.title)
        }
    )
}

Обратите внимание, что при нажатии зедсь вызывается функция popUpTo(), чтобы гарантировать, что если пользователь нажмет кнопку "Назад", навигация вернется к начальному пункту назначения. Мы можем определить начальный пункт назначения, вызвав метод findStartDestination() в графе навигации:

onClick = {
    navController.navigate(navItem.route) {
        popUpTo(navController.graph.findStartDestination().id) {saveState = true}
        launchSingleTop = true
        restoreState = true
    }
},

Запустим приложение, и нашему взору предстанет очаровательная панель с иконками, нажав на которые мы сможем переходить к различным компонентами:

Навигационная панель NavigationBar в приложении на Jetpack Compose на Kotlin в Android
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850