Compose viene con un gran número de componentes creados listos básicamente para usar configurando muy pocos parámetros. Uno de ellos en un componente muy usado en las vistas de Android , el TabLayout.

Este componente nos permite tener diferentes vistas dentro de una vista padre a las cuales podemos acceder clicando en el Tab correspondiente a cada vista. 

Creando un TabLayout básico

Para este menester contamos con un componente, TabRow, el cual en su forma más básica se utiliza de la siguiente forma:

@Composable
fun TabOnlyTitle() {
    var tabIndex by remember { mutableStateOf(0) }


    val tabData = listOf(
        "MUSIC",
        "APPS",
        "MOVIES",
        "BOOKS",
    )
    TabRow(selectedTabIndex = tabIndex) {
        tabData.forEachIndexed { index, text ->
            Tab(selected = tabIndex == index,
                onClick = {
                    tabIndex = index
                },
                text = {
                    Text(text = text)
                })
        }
    }
}

La variable tabIndex nos sirve para tener guardada la posición del Tab pulsado y que en los repintados que realice Compose este dato no se vuelva a inicializar.

Dentro de la variable tabData tenemos los títulos que vamos mostrar en cada Tab.

Al componente TabRow le pasamos como parámetro el tabIndex que hemos configurado con anterioridad y dentro de la lambda que forma el contenido del dicho TabRow lo que hacemos es iterar nuestros títulos  y crear un componente Tab con cada uno de ellos.

Cada Tab posee un método onClick en el cual actualizamos el valor del tabIndex al pulsar sobre cada uno de ellos. Para saber si el Tab en cuestión es el Tab activo, comparamos el tabIndex, que es el último pulsado y por tanto el activo, con la posición que tiene ese Tab dentro del TabRow. Si es el mismo, es el Tab activo.

Y por último seteamos el texto como contenido del Tab siendo este el título que se muestra.

Creando un TabLayout con texto e iconos

En el caso anterior vemos que solo mostramos el texto como título de cada Tab, pero a este Tab podemos añadirle también un icono. Para ello lo único que tenemos que hacer es añadir el valor del icono al Tab tal que así:

@Composable
fun TabWithIcons() {

    var tabIndex by remember { mutableStateOf(0) }


    val tabData = listOf<TabItem>(
        TabItem(title = "MUSIC", icon = Icons.Default.MusicVideo),
        TabItem(title = "APPS", icon = Icons.Default.Apps),
        TabItem(title = "MOVIES", icon = Icons.Default.Movie),
        TabItem(title = "BOOKS", icon = Icons.Default.Book),
    )

    TabRow(selectedTabIndex = tabIndex) {
        tabData.forEachIndexed { index, tabData ->
            Tab(selected = tabIndex == index,
                onClick = {
                    tabIndex = index
                },
                text = {
                    Text(text = tabData.title)
                },
                icon = { Icon(tabData.icon, contentDescription = tabData.title) })
        }

    }
}

Creando un TabLayout custom

También podríamos querer crearnos nuestro Tab customizado con nuestro propio diseño y que no sea tal como el propio componente nos los da. Para este caso lo único que tenemos que hacer es crear nuestro propio diseño de vistas dentro de la lambda que dispone cada Tab para crear su contenido. 

Es tan fácil como esto:

@Composable
fun CustomTabs() {

    var tabIndex by remember { mutableStateOf(0) }


    val tabData = listOf<TabItem>(
        TabItem(title = "MUSIC", icon = Icons.Default.MusicVideo),
        TabItem(title = "APPS", icon = Icons.Default.Apps),
        TabItem(title = "MOVIES", icon = Icons.Default.Movie),
        TabItem(title = "BOOKS", icon = Icons.Default.Book),
    )

    TabRow(selectedTabIndex = tabIndex) {
        tabData.forEachIndexed { index, tabData ->


            Tab(selected = tabIndex == index,
                onClick = {
                    tabIndex = index
                }) {

                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Box(
                        modifier = Modifier
                            .padding(10.dp)
                            .clip(CircleShape)
                            .background(Color.Magenta)

                    ) {
                        Icon(
                            tabData.icon,
                            contentDescription = tabData.title,
                            modifier = Modifier.padding(5.dp)
                        )

                    }

                    Text(text = tabData.title)
                }

            }
        }

    }
}