TabRow
fun TabRow(
selectedTabIndex: Int,
modifier: Modifier = Modifier,
backgroundColor: Color = MaterialTheme.colors.primarySurface,
contentColor: Color = contentColorFor(backgroundColor),
indicator: @Composable (tabPositions: List<TabPosition>) -> Unit = @Composable { tabPositions ->
TabRowDefaults.Indicator(
Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
)
},
divider: @Composable () -> Unit = @Composable {
TabRowDefaults.Divider()
},
tabs: @Composable () -> Unit
)
selectedTabIndex: 从0开始,选中的tab的位置索引
backgroundColor:背景颜色
contentColor:文字内容颜色
indicator:游标,就是选中的那个横线的颜色
divider:最底层那条灰线
tabs:tab组件
顺道看下源码里tab,indicator,divider的层级结构
layout(tabRowWidth, tabRowHeight) {
//先放置的是tab组件
tabPlaceables.fastForEachIndexed { index, placeable ->
placeable.placeRelative(index * tabWidth, 0)
}
//接着是divider,是放置在bottom位置的
subcompose(TabSlots.Divider, divider).fastForEach {
val placeable = it.measure(constraints.copy(minHeight = 0))
placeable.placeRelative(0, tabRowHeight - placeable.height)
}
//最后放置indicator,在divider上层,也是bottom位置
subcompose(TabSlots.Indicator) {
indicator(tabPositions)
}.fastForEach {
it.measure(Constraints.fixed(tabRowWidth, tabRowHeight)).placeRelative(0, 0)
}
}
上边图片效果的代码如下
@Composable
fun circle4() {
val items = MoneyInfo.values().toList()
var selectedTabIndex by remember {
mutableStateOf(0)
}
TabRow(selectedTabIndex = selectedTabIndex,
backgroundColor = MaterialTheme.colors.onPrimary,
contentColor = MaterialTheme.colors.primary,
) {
items.forEachIndexed { index, content ->
val colorText = if (selectedTabIndex == index) {
Color.Red
} else {
MaterialTheme.colors.onSurface.copy(alpha = 0.8f)
}
Tab(selected = selectedTabIndex == index,
onClick = { selectedTabIndex = index },
modifier = Modifier.heightIn(min = 48.dp)) {
Text(text = content.name,
color = colorText,
style = MaterialTheme.typography.subtitle2,
modifier = Modifier.paddingFromBaseline(top = 20.dp))
}
}
}
}
自定义divider ,indicator
TabRow(selectedTabIndex = selectedTabIndex,
backgroundColor = MaterialTheme.colors.onPrimary,
contentColor = MaterialTheme.colors.primary,
indicator = { tabPositions ->
Box(modifier = Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex]).border(2.dp, Color.Red, RoundedCornerShape(50)).fillMaxSize())
},
divider = { Divider(Modifier.height(2.dp))}
)
本以为完事了,结果发现不行,因为下边tab点击的时候有个ripple,它的形状是矩形的,和我们这个圆角矩形不匹配,所以看下Tab的源码,看能否修改
Tab
看到那个ripple是写死的,只有颜色可以外部修改,圆角无法修改 Tab组件实际是个Column,里边可以放多个其他组件的,比如图片加文字
@Composable
fun Tab(
selected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
selectedContentColor: Color = LocalContentColor.current,
unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium),
content: @Composable ColumnScope.() -> Unit
) {
// The color of the Ripple should always the selected color, as we want to show the color
// before the item is considered selected, and hence before the new contentColor is
// provided by TabTransition.
val ripple = rememberRipple(bounded = true, color = selectedContentColor)
TabTransition(selectedContentColor, unselectedContentColor, selected) {
Column(
modifier = modifier
.selectable(
selected = selected,
onClick = onClick,
enabled = enabled,
role = Role.Tab,
interactionSource = interactionSource,
indication = ripple
)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
content = content
)
}
}
rememberRipple
public fun rememberRipple(
bounded: Boolean = true,
radius: Dp = Dp.Unspecified,
color: Color = Color.Unspecified
)
重写Tab组件的代价太大,那咋解决ripple的范围问题?
外层包裹一层Box,由box来限制范围就ok了,如下
items.forEachIndexed { index, content ->
val colorText = if (selectedTabIndex == index) {
Color.Red
} else {
MaterialTheme.colors.onSurface.copy(alpha = 0.8f)
}
Box(modifier = Modifier.clip(RoundedCornerShape(50))){
Tab(selected = selectedTabIndex == index,
onClick = { selectedTabIndex = index },
modifier = Modifier
.heightIn(min = 48.dp)) {
Text(text = content.name,
color = colorText,
style = MaterialTheme.typography.subtitle2,
modifier = Modifier.paddingFromBaseline(top = 20.dp))
}
}
}
ok,TabRow基本用法就完事了,