Exemplo Navigation Drawer com Jetpack Compose
Published: 2023-01-06 01:35:38

Esta é uma IU de gaveta de navegação feita com o Android Jetpack Compose. Ele usa o layout Scaffold. O código-fonte está disponível gratuitamente abaixo.

**MainActivity.kt**
```kotlin
package br.com.gilbercs.exjetpackcompose

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.*
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import br.com.gilbercs.exjetpackcompose.ui.MainContent
import br.com.gilbercs.exjetpackcompose.ui.components.MyButtonBar
import br.com.gilbercs.exjetpackcompose.ui.components.MyDrawer
import br.com.gilbercs.exjetpackcompose.ui.components.MyFabButton
import br.com.gilbercs.exjetpackcompose.ui.components.MyTopAppBar
import br.com.gilbercs.exjetpackcompose.ui.theme.ExJetpackComposeTheme
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ExJetpackComposeTheme {
                //Declaração de variavel
                val scaffoldState = rememberScaffoldState()
                val coroutineScope = rememberCoroutineScope()
                val context = LocalContext.current
                //Create Scaffolf layout: Onde será adiconado itens como TopBar, BottomBar, FAB ou uma gaveta.
                Scaffold(
                    scaffoldState = scaffoldState,
                    //Top App Bar principal da aplicação
                    topBar = {
                             MyTopAppBar(
                                 onDrawerClick = {
                                     coroutineScope.launch { 
                                         scaffoldState.drawerState.open()
                                     }
                                 }
                             )
                    },
                    drawerGesturesEnabled = scaffoldState.drawerState.isOpen,
                    //Drawer Navigation da aplicação
                    drawerContent = {
                                    MyDrawer{menuTitle ->
                                        Toast.makeText(context,menuTitle,Toast.LENGTH_LONG).show()
                                        coroutineScope.launch {
                                            delay(250)
                                            scaffoldState.drawerState.close()
                                        }
                                    }
                    },
                    //Float button da aplicação
                    floatingActionButton = {
                                           MyFabButton()
                    },
                    isFloatingActionButtonDocked = true,
                    //Button da aplicação
                    bottomBar = {
                        MyButtonBar()
                    }
                ) {
                    //Scaffold content main
                    MainContent()
                }
            }
        }
    }
}

```
**MyTopAppBar**
O componente TopAppBar é freqüentemente usado como cabeçalho para nossa tela — exibindo um título de navegação junto com componentes de menu ou qualquer outra decoração que o design de nosso aplicativo exija.

```kotlin
package br.com.gilbercs.exjetpackcompose.ui.components

import android.widget.Toast
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Call
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.List
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext

@Composable
fun MyTopAppBar(
    onDrawerClick: () -> Unit
){
    val context = LocalContext.current
    val dropDownMenuItems = listOf("Menu 01", "Menu 02", "Menu 03")
    var isDropDownMenuExpanded by remember { mutableStateOf(false) }

    TopAppBar(title = { Text(text = "Meu Aplication")},
        navigationIcon = {
            IconButton(onClick = { onDrawerClick()}) {
                Icon(imageVector = Icons.Default.List, contentDescription = "Menu")
            }
        },
        actions = {
            IconButton(onClick = {
                Toast.makeText(context,"Call",Toast.LENGTH_LONG).show()
            }) {
                Icon(imageVector = Icons.Default.Call, contentDescription = "Menu", tint = Color.White)

            }
            IconButton(onClick = {
                Toast.makeText(context,"Favorito",Toast.LENGTH_LONG).show()
            }) {
                Icon(imageVector = Icons.Default.Favorite, contentDescription = "Favorite", tint = Color.White)

            }
            IconButton(onClick = {
                isDropDownMenuExpanded = true
            }) {
                Icon(imageVector = Icons.Default.MoreVert, contentDescription = "Menu", tint = Color.White)
                DropdownMenu(expanded = isDropDownMenuExpanded, onDismissRequest = { isDropDownMenuExpanded =! isDropDownMenuExpanded }) {
                    dropDownMenuItems.forEach { label->
                        DropdownMenuItem(onClick = {
                            Toast.makeText(context,"$label",Toast.LENGTH_LONG).show()
                        }) {
                            Text(text = "$label")
                        }
                    }

                }
            }
        }
    )
}
```
**MyFabButton**
Aqui você pode adicionar FloatingActionButton. Você pode definir qualquer Composable, mas FloatingActionButton já foi criado para este caso de uso.
```kotlin
import android.widget.Toast
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext

@Composable
fun MyFabButton() {
    //Declaração de variavél
    val context = LocalContext.current
    FloatingActionButton(onClick = { Toast.makeText(context,"Adicionar",Toast.LENGTH_LONG).show()},
    backgroundColor = MaterialTheme.colors.primaryVariant) {
        Icon(imageVector = Icons.Default.Add,
            contentDescription = "ADD")
    }
}
```
**MyButtonBar**
Vai exibir os destinos na parte inferior da tela. Logo vamos usa o slot bottomBar e isFloatingActionButtonDocked para sobrepor o FAB com a barra de apps inferior.

BottomAppBar oferece suporte a cortes no FAB com o parâmetro cutoutShape, que aceita qualquer Shape. É recomendável fornecer o mesmo Shape usado pelo componente fixado. Por exemplo, FloatingActionButton usa MaterialTheme.shapes.small com um tamanho de canto de 50% como valor padrão para o parâmetro shape:

```kotlin
package br.com.gilbercs.exjetpackcompose.ui.components

import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material.BottomAppBar
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable

@Composable
fun MyButtonBar() {
    BottomAppBar(
        cutoutShape = MaterialTheme.shapes.small.copy(
            CornerSize(50)
        )
    ) {
        //Buttom Content
    }
}
```
**Navigation Drawer compose**
E por fim MyDrawer da aplicação que vai ser menu deslizante para a esquerda usado para exibir o conteúdo do menu no Android.
Facilita a navegação entre diferentes telas.
A gaveta aparece quando o usuário toca no ícone do menu da gaveta na barra de aplicativos.
```kotlin
package br.com.gilbercs.exjetpackcompose.ui.components

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import br.com.gilbercs.exjetpackcompose.R

@Composable
fun MyDrawer(
    bgGradientColos: List<Color> = listOf(Color(0xFF689F38),Color(0xFF8BC34A),Color(0xFFC5E1A5)),
    onItemClick: (String) -> Unit
){
    //declarar variavel
    val itemMenu = prepareItemDrawer()

    LazyColumn(modifier = Modifier
        .fillMaxSize()
        .background(brush = Brush.verticalGradient(bgGradientColos)),
    horizontalAlignment = Alignment.CenterHorizontally,
    contentPadding = PaddingValues(vertical = 36.dp)
    ){
        item {
            //Imagem
            Image(
                modifier = Modifier
                    .size(size = 150.dp)
                    .clip(CircleShape),
                painter = painterResource(id = R.drawable.img_albert),
                contentDescription = "Imagem Perfil")
            //Text
            Text(
                modifier = Modifier.padding(top = 8.dp, bottom = 30.dp),
                text = "gilbercs@hotmail.com",
                fontWeight = FontWeight.Normal,
                fontSize = 16.sp,
                color = Color.White
            )
        }
        items(itemMenu){item ->
           NavItemDrawer(itemDrawer = item) {
               onItemClick(item.title)
           }
        }
    }

}
@Composable
fun NavItemDrawer(
    itemDrawer: ItemDrawer,
    unredBubble: Color = Color(0XFF1976D2),
    onClick: () -> Unit
){
    Row(modifier = Modifier
        .fillMaxWidth()
        .clickable { onClick() }
        .padding(24.dp, vertical = 10.dp),
    verticalAlignment = Alignment.CenterVertically) {
        Box {
            //Menu: Icon
            Icon(modifier = Modifier
                .padding(all = if (itemDrawer.show && itemDrawer.title == "Messages") 5.dp else 2.dp)
                .size(size = if (itemDrawer.show && itemDrawer.title == "Messages") 24.dp else 28.dp),
                imageVector = itemDrawer.icon,
                contentDescription = "Icon",
                tint = Color.White)
            //Unred bubble
            if (itemDrawer.show){
                Box(modifier = Modifier
                    .size(size = 8.dp)
                    .align(alignment = Alignment.TopCenter)
                    .background(color = unredBubble, shape = CircleShape))
            }
            //Menu: Title
            Text(
                modifier = Modifier
                    .padding(start = 40.dp),
                text = itemDrawer.title,
            fontSize = 20.sp,
            fontWeight = FontWeight.Medium,
            color = Color.White)
        }

    }
}
@Composable
private fun prepareItemDrawer(): List<ItemDrawer>{
    val item = arrayListOf<ItemDrawer>()
    //Adicionar Menu no Drawer: Home
    item.add(
        ItemDrawer(
            icon = Icons.Default.Home,
            title = "Home"
        )
    )
    //Perfil
    item.add(
        ItemDrawer(
            icon = Icons.Default.Person,
            title = "Perfil"
        )
    )
    //Favorite
    item.add(
        ItemDrawer(
            icon = Icons.Default.Favorite,
            title = "Favorito"
        )
    )
    //Sobre
    //Favorite
    item.add(
        ItemDrawer(
            icon = Icons.Default.Info,
            title = "Sobre"
        )
    )
    //Sair
    //Favorite
    item.add(
        ItemDrawer(
            icon = Icons.Default.Close,
            title = "Sair"
        )
    )
    return item
}
data class ItemDrawer(
    val icon: ImageVector,
    val title: String,
    val show: Boolean = false
)
```
Resultado final


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3xhvyxlfghd11hma729.gif)