1616
1717package com.example.compose.snippets.components
1818
19+ import androidx.compose.foundation.ExperimentalFoundationApi
20+ import androidx.compose.foundation.combinedClickable
21+ import androidx.compose.foundation.interaction.MutableInteractionSource
1922import androidx.compose.foundation.layout.Arrangement
23+ import androidx.compose.foundation.layout.Box
2024import androidx.compose.foundation.layout.Column
2125import androidx.compose.foundation.layout.PaddingValues
2226import androidx.compose.foundation.layout.fillMaxSize
2327import androidx.compose.foundation.layout.padding
2428import androidx.compose.foundation.lazy.LazyColumn
29+ import androidx.compose.foundation.lazy.itemsIndexed
2530import androidx.compose.material.icons.Icons
2631import androidx.compose.material.icons.automirrored.filled.ArrowBack
2732import androidx.compose.material.icons.filled.Add
@@ -30,6 +35,7 @@ import androidx.compose.material.icons.filled.Edit
3035import androidx.compose.material.icons.filled.Image
3136import androidx.compose.material.icons.filled.Menu
3237import androidx.compose.material.icons.filled.Mic
38+ import androidx.compose.material.icons.filled.Share
3339import androidx.compose.material3.BottomAppBar
3440import androidx.compose.material3.BottomAppBarDefaults
3541import androidx.compose.material3.Button
@@ -40,6 +46,7 @@ import androidx.compose.material3.FloatingActionButtonDefaults
4046import androidx.compose.material3.Icon
4147import androidx.compose.material3.IconButton
4248import androidx.compose.material3.LargeTopAppBar
49+ import androidx.compose.material3.ListItem
4350import androidx.compose.material3.MaterialTheme
4451import androidx.compose.material3.MediumTopAppBar
4552import androidx.compose.material3.Scaffold
@@ -52,6 +59,7 @@ import androidx.compose.runtime.Composable
5259import androidx.compose.runtime.getValue
5360import androidx.compose.runtime.mutableStateOf
5461import androidx.compose.runtime.remember
62+ import androidx.compose.runtime.saveable.rememberSaveable
5563import androidx.compose.runtime.setValue
5664import androidx.compose.ui.Modifier
5765import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -76,13 +84,15 @@ fun AppBarExamples(
7684 " topBarMedium" -> MediumTopAppBarExample ()
7785 " topBarLarge" -> LargeTopAppBarExample ()
7886 " topBarNavigation" -> TopBarNavigationExample { navigateBack() }
87+ " multiSelection" -> AppBarMultiSelectionExample ()
7988 else -> AppBarOptions (
8089 toBottom = { selection = " bottomBar" },
8190 toTopBarSmall = { selection = " topBar" },
8291 toTopBarCenter = { selection = " topBarCenter" },
8392 toTopBarMedium = { selection = " topBarMedium" },
8493 toTopBarLarge = { selection = " topBarLarge" },
8594 toTopBarNavigation = { selection = " topBarNavigation" },
95+ toMultiSelection = { selection = " multiSelection" },
8696 )
8797 }
8898 }
@@ -96,6 +106,7 @@ fun AppBarOptions(
96106 toTopBarMedium : () -> Unit ,
97107 toTopBarLarge : () -> Unit ,
98108 toTopBarNavigation : () -> Unit ,
109+ toMultiSelection : () -> Unit ,
99110) {
100111 Column () {
101112 Button ({ toBottom() }) {
@@ -116,6 +127,9 @@ fun AppBarOptions(
116127 Button ({ toTopBarNavigation() }) {
117128 Text (" Top bar navigation example" )
118129 }
130+ Button ({ toMultiSelection() }) {
131+ Text (" Top bar with multi selection list" )
132+ }
119133 }
120134}
121135
@@ -382,3 +396,156 @@ fun ScrollContent(innerPadding: PaddingValues) {
382396 }
383397 }
384398}
399+
400+ @OptIn(ExperimentalMaterial3Api ::class )
401+ // [START android_compose_components_appbarselectionactions]
402+ @Composable
403+ fun AppBarSelectionActions (
404+ selectedItems : Set <Int >,
405+ modifier : Modifier = Modifier ,
406+ ) {
407+ val hasSelection = selectedItems.isNotEmpty()
408+ val topBarText = if (hasSelection) {
409+ " Selected ${selectedItems.size} items"
410+ } else {
411+ " List of items"
412+ }
413+
414+ TopAppBar (
415+ title = {
416+ Text (topBarText)
417+ },
418+ colors = TopAppBarDefaults .topAppBarColors(
419+ containerColor = MaterialTheme .colorScheme.primaryContainer,
420+ titleContentColor = MaterialTheme .colorScheme.primary,
421+ ),
422+ actions = {
423+ if (hasSelection) {
424+ IconButton (onClick = {
425+ /* click action */
426+ }) {
427+ Icon (
428+ imageVector = Icons .Filled .Share ,
429+ contentDescription = " Share items"
430+ )
431+ }
432+ }
433+ },
434+ )
435+ }
436+ // [END android_compose_components_appbarselectionactions]
437+
438+ @Preview
439+ @Composable
440+ private fun AppBarSelectionActionsPreview () {
441+ val selectedItems = setOf (1 , 2 , 3 )
442+
443+ AppBarSelectionActions (selectedItems)
444+ }
445+
446+ @OptIn(ExperimentalFoundationApi ::class )
447+ @Preview
448+ // [START android_compose_components_appbarmultiselectionexample]
449+ @Composable
450+ private fun AppBarMultiSelectionExample (
451+ modifier : Modifier = Modifier ,
452+ ) {
453+ val listItems by remember { mutableStateOf(listOf (1 , 2 , 3 , 4 , 5 , 6 )) }
454+ var selectedItems by rememberSaveable { mutableStateOf(setOf<Int >()) }
455+
456+ Scaffold (
457+ topBar = { AppBarSelectionActions (selectedItems) }
458+ ) { innerPadding ->
459+ LazyColumn (contentPadding = innerPadding) {
460+ itemsIndexed(listItems) { _, index ->
461+ val isItemSelected = selectedItems.contains(index)
462+ ListItemSelectable (
463+ selected = isItemSelected,
464+ Modifier
465+ .combinedClickable(
466+ interactionSource = remember { MutableInteractionSource () },
467+ indication = null ,
468+ onClick = {
469+ /* click action */
470+ },
471+ onLongClick = {
472+ if (isItemSelected) selectedItems - = index else selectedItems + = index
473+ }
474+ )
475+ )
476+ }
477+ }
478+ }
479+ }
480+ // [END android_compose_components_appbarmultiselectionexample]
481+
482+ // [START android_compose_components_listitemselectable]
483+ @Composable
484+ fun ListItemSelectable (
485+ selected : Boolean ,
486+ modifier : Modifier = Modifier
487+ ) {
488+ Box (modifier = modifier) {
489+ ListItem (
490+ headlineContent = { Text (" Long press to select or deselect item" ) },
491+ leadingContent = {
492+ if (selected) {
493+ Icon (
494+ Icons .Filled .Check ,
495+ contentDescription = " Localized description" ,
496+ )
497+ }
498+ }
499+ )
500+ }
501+ }
502+ // [END android_compose_components_listitemselectable]
503+
504+ @Preview
505+ @Composable
506+ private fun ListItemSelectablePreview () {
507+ ListItemSelectable (true )
508+ }
509+
510+ @OptIn(ExperimentalFoundationApi ::class )
511+ // [START android_compose_components_lazylistmultiselection
512+ @Composable
513+ fun LazyListMultiSelection (
514+ listItems : List <Int >,
515+ modifier : Modifier = Modifier ,
516+ contentPadding : PaddingValues = PaddingValues (0.dp),
517+ ) {
518+ var selectedItems by rememberSaveable { mutableStateOf(setOf<Int >()) }
519+
520+ LazyColumn (contentPadding = contentPadding) {
521+ itemsIndexed(listItems) { _, index ->
522+ val selected = selectedItems.contains(index)
523+ ListItemSelectable (
524+ selected = selected,
525+ Modifier
526+ .combinedClickable(
527+ interactionSource = remember { MutableInteractionSource () },
528+ indication = null ,
529+ onClick = {
530+ /* click action */
531+ },
532+ onLongClick = {
533+ if (selected) selectedItems - = index else selectedItems + = index
534+ }
535+ )
536+ )
537+ }
538+ }
539+ }
540+ // [END android_compose_components_lazylistmultiselection
541+
542+ @Preview
543+ @Composable
544+ private fun LazyListMultiSelectionPreview () {
545+ val listItems = listOf (1 , 2 , 3 )
546+
547+ LazyListMultiSelection (
548+ listItems,
549+ modifier = Modifier
550+ )
551+ }
0 commit comments