This article introduces users of Tab, LeadingIconTab, TabRow, and ScrollableTabRow. TabRow and ScrollableTabRow are similar to the TabLayout of the previous View system. Except TabRow is non-slippable, while ScrollableTabRow is slippable. Tab is the Item control used by TabRow and ScrollableTabRow. The difference between LeadingIconTab and Tab is that LeadingIconTab has an Icon.

A: the Tab

Let’s start with the Tab code:

@Composable
fun Tab(
    selected: Boolean,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    selectedContentColor: Color = LocalContentColor.current,
    unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium),
    content: @Composable ColumnScope.() -> Unit
){
    ...
}
Copy the code
  • Selected Whether to select
  • OnClick Click event
  • Modifier Description of modifier
  • Enabled Whether it is available
  • InteractionSource can handle state, such as what happens when it’s pressed and what happens when it’s normal. Just like we did before, let’s write the Selector in the layout file. For example, in the example below, the border line is green if it is selected and black if it is not. InteractionSource. CollectIsPressedAsState () to determine whether to press state interactionSource. CollectIsFocusedAsState () Determine whether acquiring interactionSource. The focus of state collectIsDraggedAsState () to determine whether the drag We speak about the button, the button’s explanation
  • SelectedContentColor The selected color
  • UnselectedContentColor No selected color
  • The content content

For example: When Tab is pressed, the font color is red, and when selected, the font color is also red. In our example, Tab will eventually be used with TabRow, so let’s show the Tab part of the code first.

@Composable
fun tabView(index:Int,text:String,tabIndex:MutableState<Int>){
    val interactionSource = remember {
        MutableInteractionSource()
    }
    val isPress = interactionSource.collectIsPressedAsState().value
    Tab(
        selected = index == tabIndex.value,
        onClick = {
            tabIndex.value = index
        },
        modifier = Modifier
            .wrapContentWidth()
            .fillMaxHeight(),
        enabled =true,
        interactionSource = interactionSource,
        selectedContentColor = Color.Red,
        unselectedContentColor = Color.Black
    ) {
        Text(text = text,color = if(isPress || index == tabIndex.value) Color.Red else Color.Black)
    }
}
Copy the code

2: LeadingIconTab

Take a look at the LeadingIconTab code first

@ExperimentalMaterialApi
@Composable
fun LeadingIconTab(
    selected: Boolean,
    onClick: () -> Unit,
    text: @Composable(() - >Unit),
    icon: @Composable(() - >Unit),
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource()}, selectedContentColor: Color = LocalContentColor.current, unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium) ){... }Copy the code
  • Selected Whether to select
  • OnClick Click event
  • Text control
  • Icon icon controls
  • Modifier modifier
  • The classes that interactionSource handles state are the same as above
  • SelectedContentColor The selected color
  • UnselectedContentColor No selected color

For example: when Tab is pressed, the font color and Icon are red, and when selected, the font color and Icon are also red. In our example, LeadingIconTab will eventually be used with ScrollableTabRow, so we’ll give the LeadingIconTab section of the code first.

@ExperimentalMaterialApi
@Composable
fun leadingIconTabView(index:Int,text:String,tabIndex:MutableState<Int>){
    val interactionSource = remember {
        MutableInteractionSource()
    }
    val isPress = interactionSource.collectIsPressedAsState().value
    val imageVector = when(index){
        0-> Icons.Filled.Home
        1-> Icons.Filled.Shop
        2-> Icons.Filled.Favorite
        3-> Icons.Filled.School
        4-> Icons.Filled.ShoppingBag
        5-> Icons.Filled.DesktopMac
        6-> Icons.Filled.Message
        7-> Icons.Filled.FmdGood
        8-> Icons.Filled.Domain
        else ->Icons.Filled.Person
    }
    LeadingIconTab(
        selected = index == tabIndex.value,
        onClick = {
            tabIndex.value = index
        },
        text = {
            Text(text = text,color = if(isPress || index == tabIndex.value) Color.Red else Color.Black)
        },
        icon = {
            Icon(imageVector, contentDescription = "Icon icon",tint = if(isPress || index == tabIndex.value) Color.Red else Color.Black)
        },
        modifier = Modifier.wrapContentWidth().fillMaxHeight().background(Color.White),
        enabled = true,
        interactionSource = interactionSource,
        selectedContentColor = Color.Red,
        unselectedContentColor = Color.Black
    )
}
Copy the code

Three: TabRow

Let’s start with the TabRow code

@Composable
fun TabRow(
    selectedTabIndex: Int,
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    indicator: @Composable (tabPositions: List<TabPosition>) -> Unit = @Composable { tabPositions ->
        TabRowDefaults.Indicator(
            Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
        )
    },
    divider: @Composable() - >Unit = @Composable {
        TabRowDefaults.Divider()
    },
    tabs: @Composable() - >Unit
){
...
}
Copy the code
  • SelectedTabIndex Indicates the selected index position
  • Modifier modifier
  • BackgroundColor backgroundColor
  • ContentColor the contentColor
  • The line below indicator is implemented by default with tabRowDefaults. indicator. Let’s look at the tabRowDefaults.Indicator code
    @Composable
      fun Indicator(
          modifier: Modifier = Modifier,
          height: Dp = IndicatorHeight,
          color: Color = LocalContentColor.current
      ) {
          Box(
              modifier
                  .fillMaxWidth()
                  .height(height)
                  .background(color = color)
          )
      }
    Copy the code
    • Modifier modifier
    • Height height
    • Color color

    So we can actually customize it

  • Divider Divider The line below the divider tabRow is a divider. The default implementation is tabRowdefaults.divider (). Dividers We talked about dividers in an earlier article
  • Tabs tabRow content
@Preview()
@Composable
fun tabRowTest(a){
    val tabIndex = remember {
        mutableStateOf(0)}val tabDatas = ArrayList<String>().apply {
        add("Chinese")
        add("Mathematics")
        add("English")
    }
    TabRow(
        selectedTabIndex = tabIndex.value,
        modifier = Modifier
            .fillMaxWidth()
            .height(50.dp),
        backgroundColor = Color.Green,
        contentColor = Color.Black,
        divider = {
            TabRowDefaults.Divider()
        },
        indicator = {
            TabRowDefaults.Indicator(
                Modifier.tabIndicatorOffset(it[tabIndex.value]),
                color = Color.Blue,
                height = 2.dp
            )
        }
    ) {
        tabDatas.forEachIndexed{
                index, s ->
            tabView(index,s,tabIndex)
        }
    }
}

@Composable
fun tabView(index:Int,text:String,tabIndex:MutableState<Int>){
    val interactionSource = remember {
        MutableInteractionSource()
    }
    val isPress = interactionSource.collectIsPressedAsState().value
    Tab(
        selected = index == tabIndex.value,
        onClick = {
            tabIndex.value = index
        },
        modifier = Modifier
            .wrapContentWidth()
            .fillMaxHeight(),
        enabled =true,
        interactionSource = interactionSource,
        selectedContentColor = Color.Red,
        unselectedContentColor = Color.Black
    ) {
        Text(text = text,color = if(isPress || index == tabIndex.value) Color.Red else Color.Black)
    }
}
Copy the code

TabRow defaults to items that split the width of the TabRow. The ScrollableTabRow Item will be of an adaptive width type

Four: ScrollableTabRow

Let’s start with the code for ScrollableTabRow

@Composable
fun ScrollableTabRow(
    selectedTabIndex: Int,
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    edgePadding: Dp = TabRowDefaults.ScrollableTabRowPadding,
    indicator: @Composable (tabPositions: List<TabPosition>) -> Unit = @Composable { tabPositions ->
        TabRowDefaults.Indicator(
            Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
        )
    },
    divider: @Composable() - >Unit = @Composable {
        TabRowDefaults.Divider()
    },
    tabs: @Composable() - >Unit) {... }Copy the code
  • SelectedTabIndex Indicates the selected index
  • Modifier modifier
  • BackgroundColor backgroundColor
  • ContentColor the contentColor
  • EdgePadding is the size of the margin at the beginning and end of the ScrollableTabRow and the default is 54DP
  • The bottom line matches the top line when indicator is selected
  • Divider ScrollableTabRow The line below the divider is the same as the line above
  • Tabs Content of ScrollableTabRow

For example, there are nine tabs. TAB is a LeadingIconTab with an Icon. The Icon and text turn red when selected or pressed.

@ExperimentalMaterialApi
@Preview()
@Composable
fun scrollableTabRowTest(a){
    val tabIndex = remember {
        mutableStateOf(0)}val tabDatas = ArrayList<String>().apply {
        add("第1tab")
        add("第2tab")
        add("The third TAB")
        add("The fourth TAB")
        add("第5tab")
        add("第6tab")
        add("第7tab")
        add("Eighth TAB")
        add("第9tab")
    }
    ScrollableTabRow(
        selectedTabIndex = tabIndex.value,
        modifier = Modifier
            .fillMaxWidth()
            .height(50.dp),
        backgroundColor = Color.White,
        contentColor = Color.Black,
        edgePadding = 10.dp,
        divider = {
            TabRowDefaults.Divider(color = Color.Red)
        },
        indicator = {
            TabRowDefaults.Indicator(
                Modifier.tabIndicatorOffset(it[tabIndex.value]),
                color = Color.Blue,
                height = 2.dp
            )
        },
        tabs = {
            tabDatas.forEachIndexed{
                    index, s ->
                leadingIconTabView(index,s,tabIndex)
            }
        })
}


@ExperimentalMaterialApi
@Composable
fun leadingIconTabView(index:Int,text:String,tabIndex:MutableState<Int>){
    val interactionSource = remember {
        MutableInteractionSource()
    }
    val isPress = interactionSource.collectIsPressedAsState().value
    val imageVector = when(index){
        0-> Icons.Filled.Home
        1-> Icons.Filled.Shop
        2-> Icons.Filled.Favorite
        3-> Icons.Filled.School
        4-> Icons.Filled.ShoppingBag
        5-> Icons.Filled.DesktopMac
        6-> Icons.Filled.Message
        7-> Icons.Filled.FmdGood
        8-> Icons.Filled.Domain
        else ->Icons.Filled.Person
    }
    LeadingIconTab(
        selected = index == tabIndex.value,
        onClick = {
            tabIndex.value = index
        },
        text = {
            Text(text = text,color = if(isPress || index == tabIndex.value) Color.Red else Color.Black)
        },
        icon = {
            Icon(imageVector, contentDescription = "Icon icon",tint = if(isPress || index == tabIndex.value) Color.Red else Color.Black)
        },
        modifier = Modifier.wrapContentWidth().fillMaxHeight().background(Color.White),
        enabled = true,
        interactionSource = interactionSource,
        selectedContentColor = Color.Red,
        unselectedContentColor = Color.Black
    )
}
Copy the code