TabRow
Android
Component in Tv Material Compose
TV-Material Design Horizontal TabRow
Display all tabs in a set simultaneously and if the tabs exceed the container size, it has scrolling to navigate to next tab. They are best for switching between related content quickly, such as between transportation methods in a map. To navigate between tabs, use d-pad left or d-pad right when focused.
A TvTabRow contains a row of []s, and displays an indicator underneath the currently selected tab. A TvTabRow places its tabs offset from the starting edge, and allows scrolling to tabs that are placed off screen.
Last updated:
Installation
dependencies {
implementation("androidx.tv:tv-material:1.0.0")
}
Overloads
@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
name | description |
---|---|
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:* tabPositions: list of [DpRect] which provides the position of each tab* doesTabRowHaveFocus: whether any [Tab] within [TabRow] is focused |
tabs | a composable which will render all the tabs |
Code Examples
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)
)
}
}
}
}
}
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)
)
}
}
}
}
}
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)
)
}
}
}
}
}
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)
)
}
}
}
}
}
}