Search code examples
android-jetpack-composeandroid-jetpack

How to make custom tab indicator to be a rounded bar in Jetpack Compose


The following picture shows what I want to achieve. I want the tab indicator to be a short rounded bar.

expected

I looked up the implementation of TabRowDefaults.Indicator(), and just made my own one. I just tried to add the clip() modifier, but it didn't work. And I tried to change the order of the modifiers, but still no luck.

And here is my code implementation:

@Composable
fun TabLayout(
    tabItems: List<String>,
    content: @Composable () -> Unit
) {
    var tabIndex by remember { mutableStateOf(0) }
    Column {
        ScrollableTabRow(
            selectedTabIndex = tabIndex,
            edgePadding = 0.dp,
            backgroundColor = MaterialTheme.colors.background,
            contentColor = Blue100,
            indicator = { tabPositions ->
                Box(
                    modifier = Modifier
                        .tabIndicatorOffset(tabPositions[tabIndex])
                        .height(4.dp)
                        .clip(RoundedCornerShape(8.dp)) // clip modifier not working
                        .padding(horizontal = 28.dp)
                        .background(color = AnkiBlue100)
                )
            },
            divider = {},
        ) {
            tabItems.forEachIndexed { index, item ->
                Tab(
                    selected = tabIndex == index,
                    onClick = { tabIndex = index },
                    selectedContentColor = Blue100,
                    unselectedContentColor = Gray200,
                    text = {
                        Text(text = item, fontFamily = fontOutfit, fontSize = 18.sp)
                    }
                )
            }
        }
        Divider(
            color = Gray50,
            modifier = Modifier
                .fillMaxWidth()
                .padding(vertical = 4.dp)
        )
        content()
    }
}

Solution

  • You applied Modifier.padding between Modifier.clip and Modifier.background, so the rounding is actually applied to the transparent padding. You need to move the padding in front of the clip, or specify the shape with the background:

    .background(color = AnkiBlue100, shape = RoundedCornerShape(8.dp))
    

    Read more about why the order of the modifiers matters in this answer