Андроид-приложение, 25-я неделя

Обновлено 2 мая 2024 года.

Для приложения «Обеденный поднос» я решил создать проект самостоятельно, а не копировать готовый из Гитхаба.

(Версию целевого АПИ я выбираю самую раннюю из доступных в мастере создания проектов, двадцать первую.)

Потребовались кое-какие модификации файлов проекта.

Добавление навигации: последовательность действий

Ниже — черновик шпаргалки.

1. Создать класс-перечисление с заголовками:

import androidx.annotation.StringRes
...
enum class AppScreen(@StringRes val title: Int) {
    Start(title = R.string.[?название приложения?]>
    MenuWun(title = R.string.[?заголовок первый?]>
    MenuTwo(title = R.string.[?заголовок второй?]>
    ...
}

2. Создать контроллер навигации (the navigation controller):

import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
...
@Composable
fun App(
    ...
    navController: NavHostController = rememberNavController(),
) {
    ...
}

3. Создать элемент стека возврата (the backstack entry):

import androidx.navigation.compose.currentBackStackEntryAsState
...
@Composable
fun App(
    ...
    navController: ...
) {
    val backStackEntry by navController.currentBackStackEntryAsState()
    ...
}

4. Сохранить название текущего экрана:

@Composable
fun App(
    ...
) {
    val backStackEntry...
    val currentScreen = AppScreen.valueOf(
        backStackEntry?.destination?.route ?: AppScreen.Start.name
    )
    ...
}

5. Создать верхнюю плашку, то есть (а) добавить соответствующий компо́усэбэл и (б) вызвать этот компо́усэбэл из компо́усэбла приложения.

import androidx.compose.ui.Modifier
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.Text
import androidx.compose.ui.res.stringResource
...
@Composable
fun AppBar(
    currentScreen: AppScreen,
    canNavigateBack: Boolean,
    navigateUp: () -> Unit,
    modifier: Modifier = Modifier,
) {
    TopAppBar(
        title = { Text(stringResource(id = currentScreen.title)) },
        ...
    )
}

@Composable
fun App(
    ...
) {
    // Здесь будет вызов компо́усэбла «Апп бар» (AppBar).
}

5.2. В созданном компо́усэбле «Апп бар» (AppBar) вызвать библиотечный компо́усэбэл «Топ апп бар» (TopAppBar).

import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.MaterialTheme
...
@Composable
fun AppBar(
    ...
) {
    TopAppBar(
        ...
        colors = TopAppBarDefaults.mediumTopAppBarColors(
            containerColor = MaterialTheme.colorScheme.primaryContainer
        ),
        modifier = modifier,
        navigationIcon = { ... },
    )
}

5.3. Параметру «навиге́йшен а́йкон» (navigationIcon) вызова «Топ апп ба́ра» (TopAppBar) передать лямбду, в которой вызвать компо́усэблы для навигационной иконки.

import androidx.compose.material3.IconButton
import androidx.compose.material3.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
...
@Composable
fun AppBar(
    ...
) {
    TopAppBar(
        ...
        navigationIcon = {
            if (canNavigateBack) {
                IconButton(onClick = navigateUp) {
                    Icon(
                        imageVector = Icons.Filled.ArrowBack,
                        contentDescription = stringResource(R.string.back_button),
                    )
                }
            }
        },
    )
}

5.4. Параметру «топ бар» (topBar) вызова компо́усэбла Леса́ (Scaffold) передать лямбду, в которой вызвать компо́усэбэл «Апп бар» (AppBar).

@Composable
fun App(
    ...
) {
    ...
    Scaffold(
        topBar = {
            AppBar(
                currentScreen = currentScreen,
                canNavigateBack = navController.previousBackStackEntry != null,
                navigateUp = { navController.navigateUp() },
            )
        },
    ) { ... }
}

6. Создать навигационный хост, поместив его внутрь лямбды — заключительного параметра вызова компо́усэбла Леса́ (Scaffold).

import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.navigation.compose.NavHost
import androidx.compose.foundation.layout.padding
import androidx.navigation.compose.composable
import com.example.myapp.ui.StartScreen
import com.example.myapp.ui.[?другой экран?]
import com.example.myapp.ui.[?третий экран?]
...
@Composable
fun App(
    ...
) {
    ...
    Scaffold(
        ...
    ) { innerPadding ->
        val uiState by viewModel.uiState.collectAsState()
        NavHost(
            navController = navController,
            startDestination = AppScreen.Start.name,
            modifier = Modifier.padding(innerPadding),
        ) {
            composable(route = AppScreen.Start.name) {
                StartScreen(...)
            }
            composable(route = ...) {
                ...
            }
            ...
        }
    }
}