Try a free component
Get familiar with Compose Examples by adding a free component in your project
🔎
Step 1
Find a component
{}
Step 2
Copy the code
🎨
Step 3
Customize away
Avatar stack
@Composable fun AvatarPhoto(imageUrl: String, modifier: Modifier = Modifier) { AsyncImage( model = imageUrl, modifier = modifier.size(40.dp).clip(CircleShape).background(Color.White).border(2.dp, Color.White, CircleShape), contentScale = ContentScale.Crop, contentDescription = "Avatar", ) } Column(Modifier.padding(24.dp), verticalArrangement = Arrangement.spacedBy(24.dp), horizontalAlignment = Alignment.CenterHorizontally) { Row(horizontalArrangement = Arrangement.spacedBy((-12).dp), verticalAlignment = Alignment.CenterVertically) { AvatarPhoto(modifier = Modifier.size(32.dp), imageUrl = "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?fit=crop&w=512&q=80") AvatarPhoto(modifier = Modifier.zIndex(25f).size(40.dp), imageUrl = "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?fit=crop&w=512&q=80") AvatarPhoto(modifier = Modifier.zIndex(50f).size(48.dp), imageUrl = "https://images.unsplash.com/photo-1567532939604-b6b5b0db2604?fit=crop&w=512&q=80") AvatarPhoto(modifier = Modifier.zIndex(25f).size(40.dp), imageUrl = "https://images.unsplash.com/photo-1540569014015-19a7be504e3a?fit=crop&w=512&q=80") AvatarPhoto(modifier = Modifier.size(32.dp), imageUrl = "https://images.unsplash.com/photo-1506863530036-1efeddceb993?fit=crop&w=512&q=80") } Row(horizontalArrangement = Arrangement.spacedBy((-12).dp), verticalAlignment = Alignment.CenterVertically) { AvatarPhoto(imageUrl = "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?fit=crop&w=512&q=80") AvatarPhoto(imageUrl = "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?fit=crop&w=512&q=80") AvatarPhoto(imageUrl = "https://images.unsplash.com/photo-1567532939604-b6b5b0db2604?fit=crop&w=512&q=80") AvatarPhoto(imageUrl = "https://images.unsplash.com/photo-1540569014015-19a7be504e3a?fit=crop&w=512&q=80") AvatarPhoto(imageUrl = "https://images.unsplash.com/photo-1506863530036-1efeddceb993?fit=crop&w=512&q=80") } }
Simple List
data class Person(val name: String, val email: String, val photoUrl: String) val items = listOf( Person(name = "Jenny", email = "jenny@email.com", photoUrl = "https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=256&q=80"), Person(name = "James", email = "james@email.com", photoUrl = "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=256&q=80"), Person(name = "Cassidy", email = "cassidy@email.com", photoUrl = "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=256&q=80"), Person(name = "Kim", email = "kim@email.com", photoUrl = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=256&q=80"), Person(name = "Samantha", email = "sam@email.com", photoUrl = "https://images.unsplash.com/photo-1580489944761-15a19d654956?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=256&q=80"), Person(name = "John", email = "john@email.com", photoUrl = "https://images.unsplash.com/photo-1580518380430-2f84c0a7fb85?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=256&q=80"), ) LazyColumn(contentPadding = PaddingValues(vertical = 20.dp)) { items(items) { item -> Surface(onClick = { /* TODO */ }, shape = MaterialTheme.shapes.large) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier.fillMaxWidth().padding(16.dp)) { AsyncImage(model = item.photoUrl, modifier = Modifier.size(58.dp).clip(CircleShape), contentScale = ContentScale.Crop, contentDescription = null) Column { Text(text = item.name, maxLines = 1, overflow = TextOverflow.Ellipsis) Spacer(Modifier.height(4.dp)) Text(text = item.email, style = MaterialTheme.typography.bodyMedium, maxLines = 1, overflow = TextOverflow.Ellipsis) } } } } }
Start aligned when large
/** * Add the following dependency to your build.gradle.kts: * * dependencies { * implementation("com.composables:core:1.11.2") * } */ val state = rememberDialogState(visible = true) LaunchedEffect(state.visible) { if (state.visible.not()) { delay(1000) state.visible = true } } BoxWithConstraints { val isCompact = maxWidth <= 600.dp Dialog(state) { Scrim(enter = fadeIn(), exit = fadeOut(), scrimColor = Color.Black.copy(0.3f)) DialogPanel( modifier = Modifier.systemBarsPadding() .padding(16.dp) .shadow(8.dp, ComposeTheme.shapes.roundL) .background(Color.White, ComposeTheme.shapes.round) .padding(24.dp), enter = scaleIn(initialScale = 0.8f) + fadeIn(tween(durationMillis = 250)), exit = scaleOut(targetScale = 0.6f) + fadeOut(tween(durationMillis = 150)) ) { Column( modifier = Modifier.let { if (isCompact) it.fillMaxWidth() else it.widthIn(min = 280.dp, max = 520.dp) }, horizontalAlignment = if (isCompact) Alignment.CenterHorizontally else Alignment.Start ) { BasicText( text = "Are you sure?", style = ComposeTheme.textStyles.base.copy( fontWeight = FontWeight.Medium, color = ComposeTheme.colors.gray900, textAlign = if (isCompact) TextAlign.Center else TextAlign.Start ) ) Spacer(Modifier.height(16.dp)) BasicText( text = "This action cannot be undone. Choose wisely.", style = ComposeTheme.textStyles.base.copy( fontWeight = FontWeight.Normal, color = ComposeTheme.colors.gray600, textAlign = if (isCompact) TextAlign.Center else TextAlign.Start ) ) Spacer(Modifier.height(24.dp)) Row( horizontalArrangement = Arrangement.spacedBy(8.dp, alignment = Alignment.End), modifier = Modifier.fillMaxWidth() ) { Box(Modifier.clip(ComposeTheme.shapes.roundL) .clickable(role = Role.Button) { state.visible = false } .border(1.dp, Color(0xFFBDBDBD), ComposeTheme.shapes.roundL) .padding(horizontal = 14.dp, vertical = 10.dp) .let { if (isCompact) it.weight(1f) else it }, contentAlignment = Alignment.Center ) { BasicText( text = "Cancel", style = ComposeTheme.textStyles.base.copy( color = Color(0xFF424242), fontWeight = FontWeight.Medium ) ) } Box( Modifier.clip(ComposeTheme.shapes.roundL) .clickable(role = Role.Button) { state.visible = false }.background(Color(0xFF212121)) .padding(horizontal = 14.dp, vertical = 10.dp) .let { if (isCompact) it.weight(1f) else it }, contentAlignment = Alignment.Center ) { BasicText( text = "Continue", style = ComposeTheme.textStyles.base.copy( color = Color.White, fontWeight = FontWeight.Medium ) ) } } } } } }
VisualCardWithAction
Box(Modifier.clip(ComposeTheme.shapes.roundXL).width(400.dp)) { AsyncImage(model = "https://images.unsplash.com/photo-1521676129211-b7a9e7592e65?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=512&q=80", contentDescription = "Autumn Collection photo", contentScale = ContentScale.Crop, modifier = Modifier.aspectRatio(1f).fillMaxWidth().background(ComposeTheme.colors.gray50)) Box(Modifier.align(Alignment.TopCenter).fillMaxWidth().height(64.dp).background(Brush.verticalGradient(listOf(Color.Black.copy(alpha = 0.33f), Color.Transparent)))) Box(Modifier.align(Alignment.BottomCenter).fillMaxWidth().height(64.dp).background(Brush.verticalGradient(listOf(Color.Transparent, Color.Black.copy(alpha = 0.33f))))) BasicText("Autumn Collection", style = ComposeTheme.textStyles.xl3.copy(color = Color.White), modifier = Modifier.padding(16.dp).align(Alignment.BottomStart)) Box(Modifier.align(Alignment.TopEnd).padding(16.dp).clip(ComposeTheme.shapes.roundFull).clickable(role = Role.Button) { /* TODO */ }.background(Color.White).padding(16.dp), contentAlignment = Alignment.Center) { Image(Icons.Outlined.Favorite, contentDescription = "Favorite", colorFilter = ColorFilter.tint(ComposeTheme.colors.gray900)) } }
SettingsScreen
@Composable fun CategoryItem(title: String, icon: ImageVector, onClick: () -> Unit) { Surface( onClick = onClick, shape = MaterialTheme.shapes.medium, ) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 16.dp), horizontalArrangement = Arrangement.spacedBy(30.dp)) { Icon(icon, contentDescription = null, modifier = Modifier.size(28.dp), tint = MaterialTheme.colorScheme.onSurface) Text(title, style = MaterialTheme.typography.bodyLarge) } } } @Composable fun AppVersion(versionText: String, copyrights: String, onClick: () -> Unit) { Surface(onClick = onClick) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 12.dp), horizontalArrangement = Arrangement.spacedBy(30.dp)) { Box( modifier = Modifier.size(30.dp), ) Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { Text(versionText, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurface.copy(0.44f)) Text(copyrights, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurface.copy(0.44f)) } } } } val listState = rememberLazyListState() val hasScrolled by remember { derivedStateOf { listState.firstVisibleItemScrollOffset > 0 } } val appBarElevation by animateDpAsState(targetValue = if (hasScrolled) 4.dp else 0.dp) Scaffold( containerColor = MaterialTheme.colorScheme.surface, contentColor = MaterialTheme.colorScheme.onSurface, topBar = { CenterAlignedTopAppBar( colors = TopAppBarDefaults.topAppBarColors( containerColor = if (isSystemInDarkTheme()) { MaterialTheme.colorScheme.surfaceVariant.copy(alpha = if (hasScrolled) 1f else 0f) } else { MaterialTheme.colorScheme.surface }, ), modifier = Modifier.shadow(appBarElevation), title = { Text(text = "Settings") }, navigationIcon = { IconButton(onClick = { /*TODO*/ }) { Icon(Icons.AutoMirrored.Rounded.ArrowBack, contentDescription = "Go back") } }, actions = { }, ) }, ) { padding -> Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter) { LazyColumn(contentPadding = padding, modifier = Modifier.widthIn(max = 600.dp), state = listState) { item { CategoryItem(title = "Account", icon = Icons.Outlined.AccountCircle, onClick = { /*TODO*/ }) } item { CategoryItem(title = "Payment methods", icon = Icons.Outlined.CreditCard, onClick = { /*TODO*/ }) } item { CategoryItem(title = "Privacy", icon = Icons.Outlined.Lock, onClick = { /*TODO*/ }) } item { CategoryItem(title = "Notifications", icon = Icons.Outlined.Notifications, onClick = { /*TODO*/ }) } item { CategoryItem(title = "Look & Feel", icon = Icons.Outlined.Style, onClick = { /*TODO*/ }) } item { HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp)) } item { CategoryItem(title = "FAQ", icon = Icons.Outlined.QuestionMark, onClick = { /*TODO*/ }) } item { CategoryItem(title = "Send Feedback", icon = Icons.Outlined.Email, onClick = { /*TODO*/ }) } item { CategoryItem(title = "See what's new", icon = Icons.Outlined.AutoAwesome, onClick = { /*TODO*/ }) } item { HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp)) } item { CategoryItem(title = "Legal", icon = Icons.Outlined.Description, onClick = { /*TODO*/ }) } item { CategoryItem(title = "Licenses", icon = Icons.Outlined.Handshake, onClick = { /*TODO*/ }) } item { HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp)) } item { AppVersion(versionText = "Version 1.0.0", copyrights = "© 2024 Your Company", onClick = { /* TODO Add easter egg after 8 times is clicked */ }) } } } }
MusicPlayerControls
var isPlaying by remember { mutableStateOf(false) } val repeatModes = listOf("off", "once", "all") var repeatMode by remember { mutableStateOf(repeatModes[0]) } var shuffle by remember { mutableStateOf(false) } Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp), ) { IconButton( onClick = {/*TODO Enable shuffle mode*/ shuffle = shuffle.not() }, ) { val icon = when (shuffle) { true -> Lucide.Shuffle false -> Lucide.Shuffle } Icon( imageVector = icon, contentDescription = "Forward 5 seconds", modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary ) } IconButton(onClick = {/*TODO Skip to previous media item*/ }) { Icon( imageVector = Lucide.SkipBack, contentDescription = "Play Previous", modifier = Modifier.size(36.dp), tint = MaterialTheme.colorScheme.primary ) } FilledIconButton(onClick = {/*TODO toggle playback*/ isPlaying = !isPlaying }, modifier = Modifier.size(64.dp), shape = CircleShape) { if (isPlaying) { Icon(imageVector = Lucide.Pause, contentDescription = "Pause", modifier = Modifier.size(48.dp)) } else { Icon(imageVector = Lucide.Play, contentDescription = "Play", modifier = Modifier.size(48.dp)) } } IconButton(onClick = {/*TODO Skip to previous media item*/ }) { Icon( imageVector = Lucide.SkipForward, contentDescription = "Play Next", modifier = Modifier.size(36.dp), tint = MaterialTheme.colorScheme.primary ) } IconButton( onClick = { repeatMode = repeatModes[(repeatModes.indexOf(repeatMode) + 1) % repeatModes.size] }, ) { val icon = when (repeatMode) { "once" -> Lucide.Repeat1 "all" -> Lucide.Repeat2 else -> Lucide.Repeat } Icon( imageVector = icon, contentDescription = "Forward 5 seconds", modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary ) } }
Simple dropdown
/** * Add the following dependency to your build.gradle.kts: * * dependencies { * implementation("com.composables:core:1.11.2") * } */ Box(Modifier.height(300.dp).fillMaxWidth()) { Menu(modifier = Modifier.align(Alignment.TopCenter).width(240.dp), state = rememberMenuState(expanded = true)) { MenuButton( Modifier.clip(RoundedCornerShape(6.dp)).background(Color.White) .border(1.dp, Color(0xFFBDBDBD), RoundedCornerShape(6.dp)) ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = 14.dp, vertical = 10.dp) ) { BasicText("Options", style = TextStyle(fontWeight = FontWeight(500))) Spacer(Modifier.width(4.dp)) Image(Icons.Rounded.KeyboardArrowDown, null) } } MenuContent( modifier = Modifier.padding(top = 4.dp).width(320.dp).clip(RoundedCornerShape(6.dp)) .border(1.dp, Color(0xFFE0E0E0), RoundedCornerShape(6.dp)).background(Color.White).padding(4.dp), exit = fadeOut() ) { MenuItem(modifier = Modifier.clip(RoundedCornerShape(6.dp)), onClick = { /* TODO handle click */ }) { BasicText("Option 1", Modifier.fillMaxWidth().padding(vertical = 10.dp, horizontal = 10.dp)) } MenuItem(modifier = Modifier.clip(RoundedCornerShape(6.dp)), onClick = { /* TODO handle click */ }) { BasicText("Option 2", Modifier.fillMaxWidth().padding(vertical = 10.dp, horizontal = 10.dp)) } MenuItem(modifier = Modifier.clip(RoundedCornerShape(6.dp)), onClick = { /* TODO handle click */ }) { BasicText("Option 3", Modifier.fillMaxWidth().padding(vertical = 10.dp, horizontal = 10.dp)) } } } }
Modal sheet with vertical actions
/** * Add the following dependency to your build.gradle.kts: * * dependencies { * implementation("com.composables:core:1.11.2") * implementation("com.composables:icons-lucide:1.0.0") * } */ BoxWithConstraints { val isCompact = maxWidth < 600.dp val items = remember { listOf( Lucide.Share2 to "Share", Lucide.Link to "Get Link", Lucide.Pencil to "Edit name", Lucide.Trash to "Delete items", ) } val state = rememberModalBottomSheetState( initialDetent = SheetDetent.FullyExpanded ) LaunchedEffect(state.isIdle) { if (state.isIdle && state.targetDetent == SheetDetent.Hidden) { delay(500) state.currentDetent = SheetDetent.FullyExpanded } } ModalBottomSheet(state) { Scrim(scrimColor = Color.Black.copy(0.3f), enter = fadeIn(), exit = fadeOut()) Sheet(Modifier .padding(top = 12.dp) .let { if (isCompact) it else it.padding(horizontal = 56.dp) } .statusBarsPadding() .padding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal).asPaddingValues()) .shadow(4.dp, RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp)) .clip(RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp)) .background(Color.White) .widthIn(max = 640.dp) .fillMaxWidth()) { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.navigationBarsPadding() ) { DragIndication( modifier = Modifier.padding(top = 22.dp) .background(Color.Black.copy(0.4f), ComposeTheme.shapes.roundFull) .width(32.dp) .height(4.dp) ) Spacer(Modifier.height(16.dp)) items.forEach { item -> Row( horizontalArrangement = Arrangement.spacedBy(32.dp), modifier = Modifier .clickable { /* TODO */ } .clip(ComposeTheme.shapes.round) .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 14.dp), ) { Icon(item.first, null, tint = ComposeTheme.colors.gray600) BasicText(item.second) } } Spacer(Modifier.height(16.dp)) } } } }
Accordion
LazyColumn { item { var expanded by remember { mutableStateOf(false) } val degrees by animateFloatAsState(if (expanded) -90f else 90f) Column { Row(modifier = Modifier.clip(ComposeTheme.shapes.roundL).clickable { expanded = expanded.not() } .fillMaxWidth().padding(16.dp), horizontalArrangement = Arrangement.SpaceBetween) { BasicText("How do I create a new account?", style = ComposeTheme.textStyles.base) Image( Lucide.ChevronRight, contentDescription = null, modifier = Modifier.rotate(degrees), colorFilter = ColorFilter.tint(ComposeTheme.colors.gray800) ) } AnimatedVisibility( visible = expanded, enter = expandVertically( spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold ) ), exit = shrinkVertically() ) { Box(Modifier.fillMaxWidth().padding(16.dp)) { BasicText( "To create a new account, please follow these steps:\n\n" + "1. Open the app.\n" + "2. Tap on the 'Sign Up' button.\n" + "3. Fill in your details, including your name, email address, and password.\n" + "4. Click 'Create Account'.\n" + "5. You will receive a confirmation email to verify your account. Follow the instructions in the email to complete the registration process.", style = ComposeTheme.textStyles.sm ) } } Box(Modifier.fillMaxWidth().height(1.dp).background(ComposeTheme.colors.gray100)) } } item { var expanded by remember { mutableStateOf(false) } val degrees by animateFloatAsState(if (expanded) -90f else 90f) Column { Row(modifier = Modifier.clip(ComposeTheme.shapes.roundL).clickable { expanded = expanded.not() } .fillMaxWidth().padding(16.dp), horizontalArrangement = Arrangement.SpaceBetween) { BasicText("How can I reset my password?", style = ComposeTheme.textStyles.base) Image( Lucide.ChevronRight, contentDescription = null, modifier = Modifier.rotate(degrees).size(24.dp) ) } AnimatedVisibility( visible = expanded, enter = expandVertically( spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold ) ), exit = shrinkVertically() ) { Box(Modifier.fillMaxWidth().padding(16.dp)) { BasicText( "If you need to reset your password, here's what you should do:\n" + "1. On the app's login screen, tap on the 'Forgot Password?' link.\n" + "2. Enter your registered email address.\n" + "3. You will receive an email with a password reset link.\n" + "4. Click on the link and follow the instructions to reset your password.\n" + "5. Once your password is reset, you can log in with your new password.", style = ComposeTheme.textStyles.sm ) } } Box(Modifier.fillMaxWidth().height(1.dp).background(ComposeTheme.colors.gray100)) } } item { var expanded by remember { mutableStateOf(false) } val degrees by animateFloatAsState(if (expanded) -90f else 90f) Column { Row(modifier = Modifier.clip(ComposeTheme.shapes.roundL).clickable { expanded = expanded.not() } .fillMaxWidth().padding(16.dp), horizontalArrangement = Arrangement.SpaceBetween) { BasicText("How do I update my profile information?", style = ComposeTheme.textStyles.base) Image( Lucide.ChevronRight, contentDescription = null, modifier = Modifier.rotate(degrees).size(24.dp) ) } AnimatedVisibility( visible = expanded, enter = expandVertically( spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold ) ), exit = shrinkVertically() ) { Box(Modifier.fillMaxWidth().padding(16.dp)) { BasicText( "To update your profile information, please follow these steps:\n" + "1. Log in to your account.\n" + "2. Go to the 'Profile' section of the app.\n" + "3. Click on the 'Edit Profile' button.\n" + "4. Update the information you want to change, such as your name, profile picture, or contact details.\n" + "5. Click 'Save' to save your changes.\n" + "Your profile information will be updated accordingly.", style = ComposeTheme.textStyles.sm ) } } } } }
FormLayoutFilled
val focusManager = LocalFocusManager.current LazyColumn(modifier = Modifier.widthIn(max = 480.dp), verticalArrangement = Arrangement.spacedBy(12.dp), contentPadding = PaddingValues(vertical = 24.dp)) { item { Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp)) { Surface(onClick = { /* TODO */ }, color = MaterialTheme.colorScheme.surfaceVariant, shape = CircleShape) { Box(modifier = Modifier.size(96.dp), contentAlignment = Alignment.Center) { Icon(imageVector = Icons.Outlined.CameraAlt, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant) } } Text("Add photo") } } item { var imageUrl = remember { mutableStateOf<String?>(null) } Box(Modifier.fillMaxWidth()) { AsyncImage(model = imageUrl, contentDescription = null) } } item { var text by remember { mutableStateOf("") } TextField(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), label = { Text("First name") }, value = text, onValueChange = { text = it }, singleLine = true, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Next, capitalization = KeyboardCapitalization.Words), keyboardActions = KeyboardActions { focusManager.moveFocus(FocusDirection.Next) }) } item { var text by remember { mutableStateOf("") } TextField(modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), label = { Text("Last name") }, value = text, onValueChange = { text = it }, singleLine = true, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Next, capitalization = KeyboardCapitalization.Words), keyboardActions = KeyboardActions { focusManager.moveFocus(FocusDirection.Next) }) } item { Spacer(Modifier.height(4.dp)) } item { var text by remember { mutableStateOf("") } TextField( modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), label = { Text("Phone number") }, value = text, onValueChange = { text = it }, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone, imeAction = ImeAction.Next), keyboardActions = KeyboardActions { focusManager.moveFocus(FocusDirection.Next) }, singleLine = true, ) } item { Spacer(Modifier.height(4.dp)) } item { var text by remember { mutableStateOf("") } TextField( modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), label = { Text("Email") }, value = text, onValueChange = { text = it }, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email, imeAction = ImeAction.Done), keyboardActions = KeyboardActions { focusManager.clearFocus() }, singleLine = true, ) } item { Spacer(Modifier.height(4.dp)) } item { var text by remember { mutableStateOf("") } TextField( modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), value = text, onValueChange = { text = it }, label = { Text("Country") }, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, ) } item { var text by remember { mutableStateOf("") } TextField( modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), label = { Text("Street address") }, value = text, onValueChange = { text = it }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Next), keyboardActions = KeyboardActions { focusManager.moveFocus(FocusDirection.Next) }, singleLine = true, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, ) } item { var text by remember { mutableStateOf("") } TextField( modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), label = { Text("City") }, value = text, onValueChange = { text = it }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Next), keyboardActions = KeyboardActions { focusManager.moveFocus(FocusDirection.Next) }, singleLine = true, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, ) } item { var text by remember { mutableStateOf("") } TextField( modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), label = { Text("Zip/postal code") }, value = text, onValueChange = { text = it }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions { focusManager.clearFocus() }, singleLine = true, trailingIcon = { AnimatedVisibility(visible = text.isNotBlank(), enter = fadeIn(), exit = fadeOut()) { IconButton(onClick = { text = "" }) { Icon(Icons.Outlined.Cancel, "Clear") } } }, ) } item { Text(text = "Groups", style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 8.dp)) } item { var selected by remember { mutableStateOf<Int?>(null) } val options = listOf("Family", "Friends", "Work", "Other") Column { options.forEachIndexed { i, option -> Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp), modifier = Modifier.clickable { selected = i }.fillMaxWidth().padding(16.dp)) { RadioButton(selected = selected == i, onClick = null) Text(text = option) } } } } item { Text(text = "Notification Options", style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 8.dp)) } item { var selected by remember { mutableStateOf(false) } Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp), modifier = Modifier.clickable { selected = selected.not() }.fillMaxWidth().padding(16.dp)) { Checkbox(checked = selected, onCheckedChange = null) Text(text = "Override 'Do not Disturb'") } } item { var selected by remember { mutableStateOf(false) } Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(24.dp), modifier = Modifier.clickable { selected = selected.not() }.fillMaxWidth().padding(16.dp)) { Checkbox(checked = selected, onCheckedChange = null) Text(text = "Block calls from this contact") } } }
SupportingPane
var navigationIndex by remember { mutableStateOf(0) } val scope = rememberCoroutineScope() val widthSizeClass = calculateWindowSizeClass().widthSizeClass val navigationItems = listOf( mapOf("icon" to Icons.AutoMirrored.Outlined.Message, "label" to "Messages"), mapOf("icon" to Icons.Outlined.Photo, "label" to "Photos"), mapOf("icon" to Icons.Outlined.VideoCall, "label" to "Videos"), mapOf("icon" to Icons.Outlined.Games, "label" to "Games"), ) @Composable fun ContentPanel(modifier: Modifier = Modifier) { // TODO replace the contents of this composable with your own content Box(modifier.padding(16.dp).border(1.dp, MaterialTheme.colorScheme.outline, RoundedCornerShape(18.dp)).clip(RoundedCornerShape(18.dp)).background(MaterialColors.Gray[100])) } @Composable fun SupportPane(modifier: Modifier = Modifier) { // TODO replace the contents of this composable with your own content Box(modifier.padding(16.dp).border(1.dp, MaterialTheme.colorScheme.outline, RoundedCornerShape(18.dp)).clip(RoundedCornerShape(18.dp)).background(MaterialColors.Gray[100])) } if (widthSizeClass in listOf(WindowWidthSizeClass.Compact, WindowWidthSizeClass.Medium)) { val drawerState = rememberDrawerState(DrawerValue.Closed) ModalNavigationDrawer( modifier = Modifier.fillMaxHeight(), drawerState = drawerState, drawerContent = { ModalDrawerSheet { Column { Icon(imageVector = Icons.Rounded.Token, contentDescription = null, modifier = Modifier.padding(16.dp).size(48.dp), tint = MaterialTheme.colorScheme.primary) Spacer(Modifier.height(12.dp)) navigationItems.forEachIndexed { index, map -> val icon = map.get("icon") as ImageVector val label = map.get("label") as String NavigationDrawerItem(icon = { Icon(icon, contentDescription = null) }, label = { Text(label) }, selected = index == navigationIndex, onClick = { scope.launch { drawerState.close() } navigationIndex = index }, modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)) } } } }, ) { Scaffold( topBar = { TopAppBar(title = { Text(navigationItems[navigationIndex].get("label") as String) }, navigationIcon = { IconButton(onClick = { scope.launch { drawerState.open() } }) { Icon(Icons.Rounded.Menu, "Show menu") } }) }, ) { contentPadding -> Column(Modifier.padding(contentPadding).fillMaxSize()) { ContentPanel(Modifier.weight(1f).fillMaxWidth()) HorizontalDivider() SupportPane(Modifier.weight(1f).fillMaxWidth()) } } } } else { Scaffold { PermanentNavigationDrawer(drawerContent = { PermanentDrawerSheet(Modifier.width(200.dp)) { Column(Modifier.padding(vertical = 24.dp)) { ExtendedFloatingActionButton( onClick = { /*TODO*/ }, modifier = Modifier.padding(horizontal = 12.dp), ) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start)) { Icon(Icons.Outlined.Edit, null) Text("Compose") } } Spacer(Modifier.height(24.dp)) LazyColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) { itemsIndexed(navigationItems) { index, map -> val item = navigationItems.get(index) val icon = item.get("icon") as ImageVector val label = item.get("label") as String NavigationDrawerItem(modifier = Modifier.padding(horizontal = 16.dp), selected = index == navigationIndex, icon = { Icon(icon, null) }, label = { Text(label) }, onClick = { navigationIndex = index }) } } } } }, content = { Row { ContentPanel(Modifier.weight(1f).fillMaxHeight()) VerticalDivider() SupportPane(Modifier.width(360.dp).fillMaxHeight()) } }) } }
Phone
Sit tight. We are loading your preview
Avatar stack