Compose provides a large number based on the Material Design of composable and androidx.com pose. Material: Material dependencies. The Material component makes heavy use of the slot API, a pattern introduced by Compose that brings a layer of customization on top of composable items. Scaffold is typical of slots. This article will introduce TopAppBar, BottomAppBar, SnackBar and the use of Scaffold.

A: TopAppBar

Let’s take a look at the TopBar code

@Composable
fun TopAppBar(
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    elevation: Dp = AppBarDefaults.TopAppBarElevation,
    contentPadding: PaddingValues = AppBarDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
){
    ...
}
Copy the code
  • Modifier Detailed explanation of the use of modifier
  • BackgroundColor backgroundColor
  • ContentColor Specifies the color of the content
  • Elevation shadow
  • ContentPadding content margin can be set up by PaddingValue, also can use the default AppBarDefaults. ContentPadding
  • Content control

For example, the Icon of menu is on the left and the title is on the right

@Preview
@Composable
fun topBarView(a){
    TopAppBar(
        modifier = Modifier
            .fillMaxWidth()
            .height(48.dp),
        backgroundColor = MaterialTheme.colors.primarySurface,
        elevation = 4.dp,
        contentPadding = AppBarDefaults.ContentPadding
    ) {
        Row(modifier = Modifier.fillMaxWidth(),verticalAlignment = Alignment.CenterVertically) {
            Icon(
                imageVector = Icons.Filled.Menu,
                contentDescription = "Menu button",
                tint = Color.White,
                modifier = Modifier
                    .clickable {
                        // Click the button
                    }
                    .padding(start = 12.dp, end = 12.dp)
                    .fillMaxHeight()
            )
            Text(text = "Page title",fontSize = 17.sp,color = Color.White)
        }
    }
}
Copy the code

2: BottomAppBar

Let’s look at BottomBar’s code

@Composable
fun BottomAppBar(
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    cutoutShape: Shape? = null,
    elevation: Dp = AppBarDefaults.BottomAppBarElevation,
    contentPadding: PaddingValues = AppBarDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
){
    ...
}
Copy the code
  • Modifier Detailed explanation of the use of modifier
  • BackgroundColor backgroundColor
  • ContentColor Specifies the color of the content
  • CutoutShape shape
  • Elevation shadow
  • ContentPadding content margin can be set up by PaddingValue, also can use the default AppBarDefaults. ContentPadding
  • Content control

So let’s say I have five tabs

@Preview
@Composable
fun bottomBarView(a){
    val posState = remember {
        mutableStateOf(0)
    }
    BottomAppBar(
        modifier = Modifier
            .fillMaxWidth()
            .height(50.dp),
        backgroundColor = Color.White,
        contentColor = Color.White,
        elevation = 4.dp,
        cutoutShape = RoundedCornerShape(4),
        contentPadding = AppBarDefaults.ContentPadding
    ) {
        Row() {
            // For example, BottomBar is 5 tabs
            val modifier = Modifier
                .fillMaxHeight()
                .weight(1f.true)
            tabItemView(0,modifier,posState)
            tabItemView(1,modifier,posState)
            tabItemView(2,modifier,posState)
            tabItemView(3,modifier,posState)
            tabItemView(4,modifier,posState)
        }
    }
}

@Composable
fun tabItemView(pos:Int,modifier: Modifier,posState:MutableState<Int>){
    Column(
        modifier=modifier.clickable {
            posState.value = pos
        }
        ,horizontalAlignment = Alignment.CenterHorizontally
        ,verticalArrangement = Arrangement.Center
    ) {
        val imageVector = when(pos){
            0->Icons.Filled.Home
            1->Icons.Filled.Message
            2->Icons.Filled.Domain
            3->Icons.Filled.Favorite
            else->Icons.Filled.Person
        }

        val message = when(pos){
            0->"Home page"
            1->"News"
            2->"Building"
            3->"Like"
            else->"I"
        }

        Icon(imageVector = imageVector, contentDescription = message,tint = if(posState.value == pos) Color.Blue else Color.Black)
        Text(text = message,fontSize = 10.sp,color = if(posState.value == pos) Color.Blue else Color.Black)
    }
}
Copy the code

Three: SnackBar

So let’s look at the code for SnackBar

@Composable
fun Snackbar(
    modifier: Modifier = Modifier,
    action: @Composable(() - >Unit)? = null,
    actionOnNewLine: Boolean = false,
    shape: Shape = MaterialTheme.shapes.small,
    backgroundColor: Color = SnackbarDefaults.backgroundColor,
    contentColor: Color = MaterialTheme.colors.surface,
    elevation: Dp = 6.dp,
    content: @Composable() - >Unit
){... }Copy the code
  • Modifier modifier
  • What control is the content of the action action
  • ActionOnNewLine indicates whether the action content is on a new line. If true, the action content is on another line, otherwise it will be superimposed on the content
  • Default is MaterialTheme shape shape. Shapes. Small is RoundedCornerShape (4) dp)
  • BackgroundColor sets the backgroundColor
  • ContentColor Sets the color of the content
  • Elevation set shadow
  • What control is content
@Preview()
@Composable
fun snackbarTest(a){
    Snackbar(
        modifier = Modifier
            .fillMaxWidth()
            .padding(10.dp),
        action = {
            TextButton(
                onClick = {
                    Log.e("ccm"."Hit the hide button.")
                }) {
                Text(text = "Hidden",color = Color.White)
            }
        },
        actionOnNewLine = true,
        shape = MaterialTheme.shapes.small,
        backgroundColor = SnackbarDefaults.backgroundColor,
        contentColor =MaterialTheme.colors.surface,
        elevation = 6.dp
    ) {
        Text(text = "Prompt message",color=Color.White,fontSize = 12.sp)
    }
}
Copy the code

Four: Scaffold

First look at the Scaffold code: we continue to master the Scaffold components with a property example

@Composable
fun Scaffold(
    modifier: Modifier = Modifier,
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    topBar: @Composable() - >Unit = {},
    bottomBar: @Composable() - >Unit = {},
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
    floatingActionButton: @Composable() - >Unit = {},
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    isFloatingActionButtonDocked: Boolean = false,
    drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
    drawerGesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    drawerScrimColor: Color = DrawerDefaults.scrimColor,
    backgroundColor: Color = MaterialTheme.colors.background,
    contentColor: Color = contentColorFor(backgroundColor),
    content: @Composable (PaddingValues) -> Unit
){
   ...
}
Copy the code
  • Modifier Detailed explanation of the use of modifier
  • Components at the top of the topBar. Usually a title bar, such as using the TopAppBar mentioned above.
  • The bottom component of the bottomBar. So let’s say we use BottomAppBar. You could have five tabs, for example
  • SnackbarHost actually sets up a Snackbar control. Let’s look at the implementation.
    @Composable
    fun SnackbarHost(
      hostState: SnackbarHostState,
      modifier: Modifier = Modifier,
      snackbar: @Composable (SnackbarData) - >Unit = { Snackbar(it)})Copy the code
    • HostState this is the SnackbarHost state
    • Modifier modifier
    • Snackbar The snackbar control. So the main thing to look at is the Snackbar control

    Take a look at the code that Snackbar(it) points into

    @Composable
    fun Snackbar(
      snackbarData: SnackbarData,
      modifier: Modifier = Modifier,
      actionOnNewLine: Boolean = false,
      shape: Shape = MaterialTheme.shapes.small,
      backgroundColor: Color = SnackbarDefaults.backgroundColor,
      contentColor: Color = MaterialTheme.colors.surface,
      actionColor: Color = SnackbarDefaults.primaryActionColor,
      elevation: Dp = 6.dp
    ) {
      val actionLabel = snackbarData.actionLabel
      val actionComposable: (@Composable() - >Unit)? = if(actionLabel ! =null) {
          @Composable {
              TextButton(
                  colors = ButtonDefaults.textButtonColors(contentColor = actionColor),
                  onClick = { snackbarData.performAction() },
                  content = { Text(actionLabel) }
              )
          }
      } else {
          null
      }
      Snackbar(
          modifier = modifier.padding(12.dp),
          content = { Text(snackbarData.message) },
          action = actionComposable,
          actionOnNewLine = actionOnNewLine,
          shape = shape,
          backgroundColor = backgroundColor,
          contentColor = contentColor,
          elevation = elevation
      )
    }
    
    
    // What is SnackbarData
     interface SnackbarData {
      val message: String
      val actionLabel: String?
      val duration: SnackbarDuration
      fun performAction(a)
      fun dismiss(a)
    }
    Copy the code

    So the snackbarHost property actually sets up a Snackbar control. The content property of the Snackbar is a Text control, and the content of the Text control is the message property of the snackbarData, and the action of the Snackbar is a TextButton, And TextButton’s behavior happens to execute the performAction for snackbarData, and the text that TextButton displays happens to be the snackBarData.actionLable property. One more SnackbarDuration

    • Duration Specifies the displayed duration. There are three SnackbarDuration. Long (display disappear automatically after 10000 l), SnackbarDuration. Short (display disappear automatically after 4000 l), SnackbarDuration. Indefinite (not disappear after the show, Unless the action button is hidden)
  • FloatingActionButton is a float button
  • FloatingActionButtonPosition floating button on the display position. The value of FabPosition can be fabPosition. End with the bottom right or fabPosition. Center with the Center
  • IsFloatingActionButtonDocked is true, there will be half the height of the cover on top bottomBar
  • DrawerContent is the drawer component that pops up on the left. Similar to the previous DrawerLayout
  • DrawerGesturesEnabled Indicates whether the drawer component on the left can be opened and closed by dragging it with a finger
  • DrawerShape Shape of a drawer component
  • Shadow of the drawerElevation drawer component
  • DrawerBackgroundColor Background color of a drawer component
  • DrawerContentColor Specifies the color of the contents of the drawer component
  • Color value of the space left on the right when the drawerScrimColor drawer component is open
  • BackgroundColor indicates the backgroundColor of the scaffold
  • ContentColor The color of the scaffold content
  • Content The content of that scaffold
  • ScaffoldState Sets the state of scaffolds, mainly the drawerState and snackbarHostState. ScaffoldState is an scaffoldState, and let’s take a look at the scaffoldState code
    @Stable
    class ScaffoldState(
      val drawerState: DrawerState,
      val snackbarHostState: SnackbarHostState
    )
    Copy the code
    • DrawerState Sets the state of drawer controls, such as open, close
    • SnackbarHostState This is to set the state of snackbarHost, such as show snackbarHost, hide snackbarHost

    For example, click on the floatingActionButton to display the snackbarHost control and click on the topBar menuIcon. Displays the drawer control.

@Preview
@Composable
fun scaffoldTest(a){
    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    val posState = remember {
        mutableStateOf(0)
    }
    Scaffold(
        scaffoldState = scaffoldState,
        topBar = {
            topBarView(scaffoldState)
        },
        bottomBar = {
            bottomBarView(posState)
        },
        // This is the SnackbarHost component
// snackbarHost,
        floatingActionButton = {
            FloatingActionButton(
                onClick = {
                    scope.launch {
                        scaffoldState.snackbarHostState.showSnackbar(
                            "Hit FloatingActionButton"."Hidden",
                            duration = SnackbarDuration.Short
                        )
                    }
                }
            ) {
                Text(text = "Open SnackbarHost",fontSize = 10.sp,color=Color.White,modifier = Modifier.padding(start=10.dp,end = 10.dp))
            }
        },
        floatingActionButtonPosition = FabPosition.End,
        // When true, half of the height is covered above the bottomBar
        isFloatingActionButtonDocked = false,
        drawerContent = {
            val modifier = Modifier
                .fillMaxWidth()
                .padding(start = 20.dp, top = 15.dp, bottom = 15.dp)
            Text(text = "drawer title",fontSize = 14.sp,modifier = modifier,textAlign = TextAlign.Left)
            Text(text = "First content of drawer",fontSize = 14.sp,modifier=modifier,textAlign = TextAlign.Left)
            Text(text = "Content 2 of drawer",fontSize = 14.sp,modifier=modifier,textAlign = TextAlign.Left)
            Text(text = "Content 3 of the drawer",fontSize = 14.sp,modifier=modifier,textAlign = TextAlign.Left)
        },
        // Represents the ability to drag a drawer control to open and close
        drawerGesturesEnabled = true,
        drawerShape = RoundedCornerShape(4.dp),
        drawerElevation = 20.dp,
        drawerBackgroundColor = MaterialTheme.colors.primarySurface,
        drawerContentColor = Color.White,
        // Color of the rest of the right hand side when the drawer control is open
        drawerScrimColor = DrawerDefaults.scrimColor,
        backgroundColor = Color.White
        // contentColor Specifies the color of the content
    ) {
        Column(modifier = Modifier.fillMaxSize(),horizontalAlignment = Alignment.CenterHorizontally,verticalArrangement = Arrangement.Center) {
            val text = when(posState.value){
                0->"Contents of the first Tab"
                1->"Contents of the second Tab"
                2->"Contents of the third Tab"
                3->"Contents of the fourth Tab"
                else-> "Contents of the fifth Tab"
            }
            Text(text = text)
        }
    }
}

// TopBar
@Composable
fun topBarView(scaffoldState:ScaffoldState){
    val scope = rememberCoroutineScope()
    TopAppBar(
        modifier = Modifier
            .fillMaxWidth()
            .height(48.dp),
        backgroundColor = MaterialTheme.colors.primarySurface,
        elevation = 4.dp,
        contentPadding = AppBarDefaults.ContentPadding
    ) {
        Row(modifier = Modifier.fillMaxWidth(),verticalAlignment = Alignment.CenterVertically) {
            Icon(
                imageVector = Icons.Filled.Menu,
                contentDescription = "Back button",
                tint = Color.White,
                modifier = Modifier
                    .clickable {
                        / / open the drawer
                        scope.launch {
                            scaffoldState.drawerState.open()
                        }
                    }
                    .padding(start = 12.dp, end = 12.dp)
                    .fillMaxHeight()
            )
            Text(text = "Page title",fontSize = 17.sp,color = Color.White)
        }
    }
}

// bottomBar
@Composable
fun bottomBarView(posState:MutableState<Int>){

    BottomAppBar(
        modifier = Modifier
            .fillMaxWidth()
            .height(50.dp),
        backgroundColor = Color.White,
        contentColor = Color.White,
        elevation = 4.dp,
        cutoutShape = RoundedCornerShape(4),
        contentPadding = AppBarDefaults.ContentPadding
    ) {
        Row() {
            // For example, BottomBar is 5 tabs
            val modifier = Modifier
                .fillMaxHeight()
                .weight(1f.true)
            tabItemView(0,modifier,posState)
            tabItemView(1,modifier,posState)
            tabItemView(2,modifier,posState)
            tabItemView(3,modifier,posState)
            tabItemView(4,modifier,posState)
        }
    }
}

@Composable
fun tabItemView(pos:Int,modifier: Modifier,posState:MutableState<Int>){
    Column(
        modifier=modifier.clickable {
            posState.value = pos
        }
        ,horizontalAlignment = Alignment.CenterHorizontally
        ,verticalArrangement = Arrangement.Center
    ) {
        val imageVector = when(pos){
            0->Icons.Filled.Home
            1->Icons.Filled.Message
            2->Icons.Filled.Domain
            3->Icons.Filled.Favorite
            else->Icons.Filled.Person
        }

        val message = when(pos){
            0->"Home page"
            1->"News"
            2->"Building"
            3->"Like"
            else->"I"
        }

        Icon(imageVector = imageVector, contentDescription = message,tint = if(posState.value == pos) Color.Blue else Color.Black)
        Text(text = message,fontSize = 10.sp,color = if(posState.value == pos) Color.Blue else Color.Black)
    }
}
Copy the code