TabIndicatorScope
-
Cmn
interface TabIndicatorScope
Scope for the composable used to render a Tab indicator, this can be used for more complex indicators requiring layout information about the tabs like TabRowDefaults.PrimaryIndicator and TabRowDefaults.SecondaryIndicator
Summary
Public functions |
||
|---|---|---|
Modifier |
Modifier.tabIndicatorLayout(A layout modifier that provides tab positions, this can be used to animate and layout a TabIndicator depending on size, position, and content size of each Tab. |
Cmn
|
Modifier |
Modifier.tabIndicatorOffset(A Modifier that follows the default offset and animation |
Cmn
|
Public functions
tabIndicatorLayout
fun Modifier.tabIndicatorLayout(
measure: MeasureScope.(Measurable, Constraints, List<TabPosition>) -> MeasureResult
): Modifier
A layout modifier that provides tab positions, this can be used to animate and layout a TabIndicator depending on size, position, and content size of each Tab.
import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.AnimationVector1D import androidx.compose.animation.core.VectorConverter import androidx.compose.animation.core.spring import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Tab import androidx.compose.material3.TabPosition import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.Measurable import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp val colors = listOf( MaterialTheme.colorScheme.primary, MaterialTheme.colorScheme.secondary, MaterialTheme.colorScheme.tertiary, ) var startAnimatable by remember { mutableStateOf<Animatable<Dp, AnimationVector1D>?>(null) } var endAnimatable by remember { mutableStateOf<Animatable<Dp, AnimationVector1D>?>(null) } val coroutineScope = rememberCoroutineScope() val indicatorColor: Color by animateColorAsState(colors[index % colors.size], label = "") Box( Modifier.tabIndicatorLayout { measurable: Measurable, constraints: Constraints, tabPositions: List<TabPosition> -> val newStart = tabPositions[index].left val newEnd = tabPositions[index].right val startAnim = startAnimatable ?: Animatable(newStart, Dp.VectorConverter).also { startAnimatable = it } val endAnim = endAnimatable ?: Animatable(newEnd, Dp.VectorConverter).also { endAnimatable = it } if (endAnim.targetValue != newEnd) { coroutineScope.launch { endAnim.animateTo( newEnd, animationSpec = if (endAnim.targetValue < newEnd) { spring(dampingRatio = 1f, stiffness = 1000f) } else { spring(dampingRatio = 1f, stiffness = 50f) }, ) } } if (startAnim.targetValue != newStart) { coroutineScope.launch { startAnim.animateTo( newStart, animationSpec = // Handle directionality here, if we are moving to the right, we // want the right side of the indicator to move faster, if we are // moving to the left, we want the left side to move faster. if (startAnim.targetValue < newStart) { spring(dampingRatio = 1f, stiffness = 50f) } else { spring(dampingRatio = 1f, stiffness = 1000f) }, ) } } val indicatorEnd = endAnim.value.roundToPx() val indicatorStart = startAnim.value.roundToPx() // Apply an offset from the start to correctly position the indicator around the tab val placeable = measurable.measure( constraints.copy( maxWidth = indicatorEnd - indicatorStart, minWidth = indicatorEnd - indicatorStart, ) ) layout(constraints.maxWidth, constraints.maxHeight) { placeable.place(indicatorStart, 0) } } .padding(5.dp) .fillMaxSize() .drawWithContent { drawRoundRect( color = indicatorColor, cornerRadius = CornerRadius(5.dp.toPx()), style = Stroke(width = 2.dp.toPx()), ) } )
tabIndicatorOffset
fun Modifier.tabIndicatorOffset(
selectedTabIndex: Int,
matchContentSize: Boolean = false
): Modifier
A Modifier that follows the default offset and animation