簡體   English   中英

在 Jetpack Compose 中使用 Navigation Drawer 在可組合組件之間導航

[英]Navigating between composable's using a Navigation Drawer in Jetpack Compose

我正在嘗試為 jetpack compose 中的抽屜圖標/文本字段設置導航,但不完全確定如何正確執行。 如何設置導航,以便每當我單擊其中一個圖標時,我都會導航到該可組合屏幕? 這是目前我的MainDrawer 布局:


@Composable
fun MainDrawer() {

    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    Scaffold(
        scaffoldState = scaffoldState,
        topBar = {
            AppBar(
                onNavigationIconClick = {
                    scope.launch {
                        scaffoldState.drawerState.isOpen
                    }
                }
            )
        },
        drawerContent = {
            DrawerHeader()
            DrawerBody(
                items = listOf(
                    MenuItem(

                        id = "item1",
                        title = "item1",
                        contentDescription = "Go to item1 screen",
                        icon = Icons.Default.Home
                    ),
                    MenuItem(
                        id = "item2",
                        title = "item2",
                        contentDescription = "Go to item2 screen",
                        icon = Icons.Default.Settings
                    ),
                    MenuItem(
                        id = "item3",
                        title = "item3",
                        contentDescription = "Ge to item3",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item4",
                        title = "item4",
                        contentDescription = "Go to Your item4",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item5",
                        title = "item5",
                        contentDescription = "Your item5",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item6",
                        title = "item6",
                        contentDescription = "Your item6",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item7",
                        title = "item7",
                        contentDescription = "item7",
                        icon = Icons.Default.Info
                    ),
                    MenuItem(
                        id = "item8",
                        title = "item8",
                        contentDescription = "item8",
                        icon = Icons.Default.Info
                    ),
                )
            ) {
                println("Clicked on ${it.title}")
            }
        }
    ) {

    }
}

抽屜主體:這包含主體的元素

@Composable
fun DrawerBody(
    items: List<MenuItem>,
    modifier: Modifier = Modifier,
    itemTextStyle: TextStyle = TextStyle(fontSize = 18.sp),
    onItemClick: (MenuItem) -> Unit
) {
    LazyColumn(modifier) {
        items(items) { item ->
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {
                        onItemClick(item)
                    }
                    .padding(16.dp)
            ) {
                Icon(
                    imageVector = item.icon,
                    contentDescription = item.contentDescription
                )
                Spacer(modifier = Modifier.width(16.dp))
                Text(
                    text = item.title,
                    style = itemTextStyle,
                    modifier = Modifier.weight(1f)
                )
            }
        }

    }

}

我設法解決了這個問題。 這就是它的工作方式: https://gyazo.com/4c32e855becff72f8979650545ad7f39

我是這樣做的:

  1. 首先將依賴項添加到您的項目中:
 // Navigation with Compose
    implementation "androidx.navigation:navigation-compose:2.5.0"

    // Modal Drawer Layout
    implementation "androidx.drawerlayout:drawerlayout:1.1.1"

 // Coroutines
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"

  1. 首先為應用程序創建 TopAppBar。 這是以下代碼:

@Composable
fun TopBar(scope: CoroutineScope, scaffoldState: ScaffoldState) {
    TopAppBar(
        title = { Text(text = stringResource(R.string.app_name), fontSize = 18.sp) },
        navigationIcon = {
            IconButton(onClick = {
                scope.launch {
                    scaffoldState.drawerState.open()
                }
            }) {
                Icon(Icons.Filled.Menu, "")
            }
        },
        backgroundColor = colorResource(id = R.color.purple_200),
        contentColor = Color.White
    )
}
  1. 接下來,創建一個密封的 class。 這個 class 將代表您在抽屜里想要的物品。 我將以下內容作為示例:
sealed class NavDrawerItem(var route: String, var icon: Int, var title: String) {
    object Add : NavDrawerItem("add", android.R.drawable.ic_menu_add, "Add")
    object Edit : NavDrawerItem("edit", android.R.drawable.ic_menu_edit, "Edit")
    object Search : NavDrawerItem("search", android.R.drawable.ic_menu_search, "Search")
    object Location : NavDrawerItem("location", android.R.drawable.ic_menu_mylocation, "Location")
    object Preferences : NavDrawerItem("preferences", android.R.drawable.ic_menu_preferences, "Preferences")
}
  1. 現在,創建熒光筆。 當抽屜中的項目被按下時,這將突出顯示已按下的項目。
@Composable
fun DrawerItem(item: NavDrawerItem, selected: Boolean, onItemClick: (NavDrawerItem) -> Unit) {
    val background = if (selected) R.color.purple_200 else android.R.color.transparent
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = { onItemClick(item) })
            .height(45.dp)
            .background(colorResource(id = background))
            .padding(start = 10.dp)
    ) {
        Image(
            painter = painterResource(id = item.icon),
            contentDescription = item.title,
            colorFilter = ColorFilter.tint(Color.White),
            contentScale = ContentScale.Fit,
            modifier = Modifier
                .height(35.dp)
                .width(35.dp)
        )
        Spacer(modifier = Modifier.width(7.dp))
        Text(
            text = item.title,
            fontSize = 18.sp,
            color = Color.White
        )
    }
}
  1. 在這里,我們為各個項目創建每個屏幕。 每個項目 1 個可組合屏幕。 我創建了一個簡單快捷的屏幕,但您可以在這里制作自己的屏幕。
@Composable
fun AddScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myColor))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Add Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun EditScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myOrange))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Edit Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun SearchScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.purple_500))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Search Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun LocationScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myGreen))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Location Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}

@Composable
fun PreferencesScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.myGreen))
            .wrapContentSize(Alignment.Center)
    ) {
        Text(
            text = "Preference Screen",
            fontWeight = FontWeight.Bold,
            color = Color.White,
            modifier = Modifier.align(Alignment.CenterHorizontally),
            textAlign = TextAlign.Center,
            fontSize = 25.sp
        )
    }
}
  1. 現在我們需要使用 navcontroller 和 navHostController 創建實際的導航。 我們通過以下方式做到這一點:
@Composable
fun ComposeNavigation(navController: NavHostController) {
    NavHost(navController, startDestination = NavDrawerItem.Add.route) {
        composable(NavDrawerItem.Add.route) {
            AddScreen()
        }
        composable(NavDrawerItem.Edit.route) {
            EditScreen()
        }
        composable(NavDrawerItem.Search.route) {
            SearchScreen()
        }
        composable(NavDrawerItem.Location.route) {
            LocationScreen()
        }
        composable(NavDrawerItem.Preferences.route) {
            PreferencesScreen()
        }
    }
}

  1. 之后,使用所有項目、協程和 navbackstack 創建 DrawerLayout。
@Composable
fun DrawerLayout(scope: CoroutineScope, scaffoldState: ScaffoldState, navController: NavController) {
    val items = listOf(
        NavDrawerItem.Add,
        NavDrawerItem.Edit,
        NavDrawerItem.Search,
        NavDrawerItem.Location,
        NavDrawerItem.Preferences
    )
    Column {
// Header
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_foreground),
            contentDescription = R.drawable.ic_launcher_foreground.toString(),
            modifier = Modifier
                .height(100.dp)
                .fillMaxWidth()
                .padding(10.dp)
        )
        Spacer(
            modifier = Modifier
                .fillMaxWidth()
                .height(5.dp)
        )
        val navBackStackEntry by navController.currentBackStackEntryAsState()
        val currentRoute = navBackStackEntry?.destination?.route
        items.forEach { item ->
            DrawerItem(item = item, selected = currentRoute == item.route, onItemClick = {
                navController.navigate(item.route) {
                    navController.graph.startDestinationRoute?.let { route ->
                        popUpTo(route) {
                            saveState = true
                        }
                    }
                    launchSingleTop = true
                    restoreState = true
                }
                scope.launch {
                    scaffoldState.drawerState.close()
                }
            })
        }
    }
}

  1. 最后,我們創建了 mainLayout,它將作為我們應用程序的主框架。 這里將為 topbar 和抽屜內容使用腳手架:
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun MainLayout() {

    val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
    val scope = rememberCoroutineScope()
    val navController = rememberNavController()

    Scaffold(
        scaffoldState = scaffoldState,
        topBar = { TopBar(scope = scope, scaffoldState = scaffoldState) },
        drawerBackgroundColor = colorResource(id = R.color.myColor),
        drawerContent = {
            DrawerLayout(scope = scope, scaffoldState = scaffoldState, navController = navController)
        },
    ) {

        ComposeNavigation(navController = navController)
    }
}

希望這有助於任何尋找功能導航抽屜的人。 如果這對您有用,請隨意給它一個箭頭。 快樂編碼!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM