Side Sheet
Material | Material 3 |
---|---|
![]() | ![]() |
El Side Sheet
es un panel deslizante que aparece desde un lado
de la pantalla (generalmente desde la derecha o la izquierda).
Se utiliza para mostrar información adicional o opciones sin
salir de la pantalla actual.
Implementación
Definición del componente
@Composablefun ModalDrawer( drawerContent: @Composable ColumnScope.() -> Unit, modifier: Modifier = Modifier, drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed), gesturesEnabled: Boolean = true, drawerShape: Shape = DrawerDefaults.shape, drawerElevation: Dp = DrawerDefaults.Elevation, drawerBackgroundColor: Color = DrawerDefaults.backgroundColor, drawerContentColor: Color = contentColorFor(drawerBackgroundColor), scrimColor: Color = DrawerDefaults.scrimColor, content: @Composable () -> Unit): Unit
Atributo | Descripción |
---|---|
drawerContent | Contenido dentro del side sheet. |
modifier | Modificador opcional para todo el componente. |
drawerState | El estado del componente. |
gesturesEnabled | Indica si se puede usar el componente con gestos. |
drawerShape | Indica la forma del componente. |
drawerElevation | Indica la elevación del componente. |
drawerBackgroundColor | Indica el color de fondo del contenedor. |
drawerContentColor | El color de contenido preferido proporcionado por el componente a sus hijos. Por defecto, es el color de contenido que coincide con sheetBackgroundColor, o si no es un color del tema, mantendrá el mismo color de contenido establecido sobre el componente. |
scrimColor | El color del velo que se aplica al resto de la pantalla cuando el componente es visible. |
content | El contenido del resto de la interfaz. |
@Composablefun ModalNavigationDrawer( drawerContent: @Composable () -> Unit, modifier: Modifier = Modifier, drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed), gesturesEnabled: Boolean = true, scrimColor: Color = DrawerDefaults.scrimColor, content: @Composable () -> Unit): Unit
Atributo | Descripción |
---|---|
drawerContent | Contenido dentro del side sheet. |
modifier | Modificador opcional para todo el componente. |
drawerState | El estado del componente. |
gesturesEnabled | Indica si se puede usar el componente con gestos. |
scrimColor | El color del velo que se aplica al resto de la pantalla cuando el componente es visible. |
content | El contenido del resto de la interfaz. |
Ejemplos

package com.example.sidesheet
import android.os.Bundleimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.activity.enableEdgeToEdgeimport androidx.compose.foundation.backgroundimport androidx.compose.foundation.clickableimport androidx.compose.foundation.layout.Boximport androidx.compose.foundation.layout.Columnimport androidx.compose.foundation.layout.Rowimport androidx.compose.foundation.layout.Spacerimport androidx.compose.foundation.layout.fillMaxSizeimport androidx.compose.foundation.layout.fillMaxWidthimport androidx.compose.foundation.layout.paddingimport androidx.compose.foundation.layout.widthimport androidx.compose.foundation.shape.RoundedCornerShapeimport androidx.compose.material.icons.Iconsimport androidx.compose.material.icons.filled.Homeimport androidx.compose.material.icons.filled.Menuimport androidx.compose.material.icons.filled.Personimport androidx.compose.material.icons.filled.Settingsimport androidx.compose.material.icons.outlined.Homeimport androidx.compose.material.icons.outlined.Personimport androidx.compose.material.icons.outlined.Settingsimport androidx.compose.material.DrawerValueimport androidx.compose.material.Iconimport androidx.compose.material.IconButtonimport androidx.compose.material.MaterialThemeimport androidx.compose.material.ModalDrawerimport androidx.compose.material.Scaffoldimport androidx.compose.material.Surfaceimport androidx.compose.material.Textimport androidx.compose.material.TopAppBarimport androidx.compose.material.rememberDrawerStateimport androidx.compose.runtime.Composableimport androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableIntStateOfimport androidx.compose.runtime.rememberimport androidx.compose.runtime.rememberCoroutineScopeimport androidx.compose.runtime.setValueimport androidx.compose.ui.Alignmentimport androidx.compose.ui.Modifierimport androidx.compose.ui.draw.clipimport androidx.compose.ui.graphics.Colorimport androidx.compose.ui.graphics.vector.ImageVectorimport androidx.compose.ui.unit.dpimport com.example.sidesheet.ui.theme.SideSheetThemeimport kotlinx.coroutines.launch
data class NavigationItem( val title: String, val selectedIcon: ImageVector, val unselectedIcon: ImageVector, val badgeCount: Int? = null)
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { SideSheetTheme { val items = listOf( NavigationItem( title = "Home", selectedIcon = Icons.Filled.Home, unselectedIcon = Icons.Outlined.Home ), NavigationItem( title = "Profile", selectedIcon = Icons.Filled.Person, unselectedIcon = Icons.Outlined.Person ), NavigationItem( title = "Settings", selectedIcon = Icons.Filled.Settings, unselectedIcon = Icons.Outlined.Settings ) ) Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val scope = rememberCoroutineScope() var selectedItem by remember { mutableIntStateOf(0) } ModalDrawer( drawerContent = { Column(modifier = Modifier.padding(vertical = 48.dp, horizontal = 16.dp)) { items.forEachIndexed { index, item -> NavigationDrawerItem(label = { Text(text = item.title, color = Color.Black) }, onClick = { selectedItem = index scope.launch { drawerState.close() } }, icon = { Icon( imageVector = if (index == selectedItem) item.selectedIcon else item.unselectedIcon, contentDescription = item.title, tint = Color.Black ) }, selected = index == selectedItem ) } } }, drawerState = drawerState, ) { Scaffold(topBar = { TopAppBar(title = { Text(text = "Side Shee Example") }, navigationIcon = { IconButton(onClick = { scope.launch { drawerState.open() } }) { Icon( imageVector = Icons.Default.Menu, contentDescription = "Menu" ) } }) }) { paddingValues -> Box( modifier = Modifier .padding(paddingValues) .padding(horizontal = 16.dp) ) { Text(text = "Hello World") } } } } } } }}
@Composablefun NavigationDrawerItem( label: @Composable () -> Unit, onClick: () -> Unit, icon: @Composable () -> Unit, modifier: Modifier = Modifier, selected: Boolean = false,) {
Row( modifier = modifier .fillMaxWidth() .clip(shape = RoundedCornerShape(24.dp)) .background(color = if (selected) MaterialTheme.colors.primary.copy(alpha = 0.25f) else Color.Transparent) .padding(vertical = 12.dp, horizontal = 16.dp) .clickable(onClick = onClick), verticalAlignment = Alignment.CenterVertically, ) { icon() Spacer(Modifier.width(12.dp)) label() }}

package com.example.sidesheet
import android.os.Bundleimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.activity.enableEdgeToEdgeimport androidx.compose.foundation.layout.Boximport androidx.compose.foundation.layout.Spacerimport androidx.compose.foundation.layout.fillMaxSizeimport androidx.compose.foundation.layout.heightimport androidx.compose.foundation.layout.paddingimport androidx.compose.material.icons.Iconsimport androidx.compose.material.icons.filled.Homeimport androidx.compose.material.icons.filled.Menuimport androidx.compose.material.icons.filled.Personimport androidx.compose.material.icons.filled.Settingsimport androidx.compose.material.icons.outlined.Homeimport androidx.compose.material.icons.outlined.Personimport androidx.compose.material.icons.outlined.Settingsimport androidx.compose.material3.DrawerValueimport androidx.compose.material3.ExperimentalMaterial3Apiimport androidx.compose.material3.Iconimport androidx.compose.material3.IconButtonimport androidx.compose.material3.MaterialThemeimport androidx.compose.material3.ModalDrawerSheetimport androidx.compose.material3.ModalNavigationDrawerimport androidx.compose.material3.NavigationDrawerItemimport androidx.compose.material3.NavigationDrawerItemDefaultsimport androidx.compose.material3.Scaffoldimport androidx.compose.material3.Surfaceimport androidx.compose.material3.Textimport androidx.compose.material3.TopAppBarimport androidx.compose.material3.rememberDrawerStateimport androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableIntStateOfimport androidx.compose.runtime.rememberimport androidx.compose.runtime.rememberCoroutineScopeimport androidx.compose.runtime.setValueimport androidx.compose.ui.Modifierimport androidx.compose.ui.graphics.vector.ImageVectorimport androidx.compose.ui.unit.dpimport com.example.sidesheet.ui.theme.SideSheetThemeimport kotlinx.coroutines.launch
data class NavigationItem( val title: String, val selectedIcon: ImageVector, val unselectedIcon: ImageVector, val badgeCount: Int? = null)
class MainActivity : ComponentActivity() { @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { SideSheetTheme { val items = listOf( NavigationItem( title = "Home", selectedIcon = Icons.Filled.Home, unselectedIcon = Icons.Outlined.Home ), NavigationItem( title = "Profile", selectedIcon = Icons.Filled.Person, unselectedIcon = Icons.Outlined.Person ), NavigationItem( title = "Settings", selectedIcon = Icons.Filled.Settings, unselectedIcon = Icons.Outlined.Settings ) ) Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val scope = rememberCoroutineScope() var selectedItem by remember { mutableIntStateOf(0) } ModalNavigationDrawer( drawerContent = { ModalDrawerSheet { Spacer(modifier = Modifier.height(24.dp)) items.forEachIndexed { index, item -> NavigationDrawerItem( label = { Text(text = item.title) }, selected = index == selectedItem, onClick = { selectedItem = index scope.launch { drawerState.close() } }, icon = { Icon( imageVector = if (index == selectedItem) item.selectedIcon else item.unselectedIcon, contentDescription = item.title ) }, badge = { item.badgeCount?.let { Text(text = item.badgeCount.toString()) } }, modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding) ) } } }, drawerState = drawerState, ) { Scaffold( topBar = { TopAppBar( title = { Text(text = "Side Shee Example") }, navigationIcon = { IconButton(onClick = { scope.launch { drawerState.open() } }) { Icon( imageVector = Icons.Default.Menu, contentDescription = "Menu" ) } } ) } ) { paddingValues -> Box( modifier = Modifier .padding(paddingValues) .padding(horizontal = 16.dp) ) { Text(text = "Hello World") } }
} } } } }}