TabRow
Composable Component
TV-Material Design Horizontal TabRow
Android
@Composable
fun TabRow(
selectedTabIndex: Int,
modifier: Modifier = Modifier,
containerColor: Color = TabRowDefaults.ContainerColor,
contentColor: Color = TabRowDefaults.contentColor(),
separator: @Composable () -> Unit = { TabRowDefaults.TabSeparator() },
indicator: @Composable (tabPositions: List<DpRect>, doesTabRowHaveFocus: Boolean) -> Unit =
@Composable { tabPositions, doesTabRowHaveFocus ->
tabPositions.getOrNull(selectedTabIndex)?.let { currentTabPosition ->
TabRowDefaults.PillIndicator(
currentTabPosition = currentTabPosition,
doesTabRowHaveFocus = doesTabRowHaveFocus,
)
}
},
tabs: @Composable TabRowScope.() -> Unit,
)
Parameters
| selectedTabIndex | the index of the currently selected tab |
| modifier | the Modifier to be applied to this tab row |
| containerColor | the color used for the background of this tab row |
| contentColor | the primary color used in the tabs |
| separator | use this composable to add a separator between the tabs |
| indicator | used to indicate which tab is currently selected and/or focused. This lambda provides 2 values: |
| tabs | a composable which will render all the tabs |
Code Examples
OnClickNavigation
/** Tab changes onClick instead of onFocus */
@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun OnClickNavigation() {
val bgColors =
listOf(
Color(0x6a, 0x16, 0x16),
Color(0x6a, 0x40, 0x16),
Color(0x6a, 0x6a, 0x16),
Color(0x40, 0x6a, 0x16),
)
var focusedTabIndex by remember { mutableStateOf(0) }
var activeTabIndex by remember { mutableStateOf(focusedTabIndex) }
Box(modifier = Modifier.fillMaxSize().background(bgColors[activeTabIndex])) {
TabRow(
selectedTabIndex = focusedTabIndex,
indicator = { tabPositions, doesTabRowHaveFocus ->
// FocusedTab's indicator
TabRowDefaults.PillIndicator(
currentTabPosition = tabPositions[focusedTabIndex],
activeColor = Color.Blue.copy(alpha = 0.4f),
inactiveColor = Color.Transparent,
doesTabRowHaveFocus = doesTabRowHaveFocus,
)
// SelectedTab's indicator
TabRowDefaults.PillIndicator(
currentTabPosition = tabPositions[activeTabIndex],
doesTabRowHaveFocus = doesTabRowHaveFocus,
)
},
modifier = Modifier.focusRestorer(),
) {
repeat(bgColors.size) {
key(it) {
Tab(
selected = activeTabIndex == it,
onFocus = { focusedTabIndex = it },
onClick = {
focusedTabIndex = it
activeTabIndex = it
},
) {
Text(
text = "Tab ${it + 1}",
fontSize = 12.sp,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 6.dp),
)
}
}
}
}
}
}
PillIndicatorTabRow
/** Tab row with a Pill indicator */
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun PillIndicatorTabRow() {
val tabs = listOf("Tab 1", "Tab 2", "Tab 3")
var selectedTabIndex by remember { mutableStateOf(0) }
TabRow(selectedTabIndex = selectedTabIndex, modifier = Modifier.focusRestorer()) {
tabs.forEachIndexed { index, tab ->
key(index) {
Tab(selected = index == selectedTabIndex, onFocus = { selectedTabIndex = index }) {
Text(
text = tab,
fontSize = 12.sp,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 6.dp),
)
}
}
}
}
}
TabRowWithDebounce
/** Tab row with delay between tab changes */
@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun TabRowWithDebounce() {
val tabs = listOf("Tab 1", "Tab 2", "Tab 3")
var selectedTabIndex by remember { mutableStateOf(0) }
// This index will be used to show a panel
var tabPanelIndex by remember { mutableStateOf(selectedTabIndex) }
// Change the tab-panel only after some delay
LaunchedEffect(selectedTabIndex) {
delay(250.microseconds)
tabPanelIndex = selectedTabIndex
}
TabRow(selectedTabIndex = selectedTabIndex, modifier = Modifier.focusRestorer()) {
tabs.forEachIndexed { index, tab ->
key(index) {
Tab(selected = index == selectedTabIndex, onFocus = { selectedTabIndex = index }) {
Text(
text = tab,
fontSize = 12.sp,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 6.dp),
)
}
}
}
}
}
UnderlinedIndicatorTabRow
/** Tab row with an Underlined indicator */
@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun UnderlinedIndicatorTabRow() {
val tabs = listOf("Tab 1", "Tab 2", "Tab 3")
var selectedTabIndex by remember { mutableStateOf(0) }
TabRow(
selectedTabIndex = selectedTabIndex,
indicator = { tabPositions, doesTabRowHaveFocus ->
TabRowDefaults.UnderlinedIndicator(
currentTabPosition = tabPositions[selectedTabIndex],
doesTabRowHaveFocus = doesTabRowHaveFocus,
)
},
modifier = Modifier.focusRestorer(),
) {
tabs.forEachIndexed { index, tab ->
key(index) {
Tab(
selected = index == selectedTabIndex,
onFocus = { selectedTabIndex = index },
colors = TabDefaults.underlinedIndicatorTabColors(),
) {
Text(
text = tab,
fontSize = 12.sp,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 6.dp),
)
}
}
}
}
}