Improve TabRow

This commit is contained in:
vfsfitvnm 2022-07-16 18:17:25 +02:00
parent c5dbc08e84
commit 4cb2add24e
3 changed files with 46 additions and 77 deletions

View file

@ -32,6 +32,17 @@ class TabPagerState(
val offset by animatable.asState()
val progress: Float
get() = if (offset >= 0) (offset / animatable.upperBound!!) else (offset / animatable.lowerBound!!)
val targetPageIndex by derivedStateOf {
tempPageIndex ?: when {
offset > 0 -> pageIndex + 1
offset < 0 -> pageIndex - 1
else -> null
}
}
fun updateBounds(lowerBound: Float, upperBound: Float) {
animatable.updateBounds(lowerBound, upperBound)
}
@ -41,14 +52,14 @@ class TabPagerState(
if (newPageIndex > pageIndex) {
animatable.animateTo(
animatable.upperBound!!, tween(
durationMillis = 3000,
durationMillis = 300,
easing = FastOutSlowInEasing
)
)
} else if (newPageIndex < pageIndex) {
animatable.animateTo(
animatable.lowerBound!!, tween(
durationMillis = 3000,
durationMillis = 300,
easing = FastOutSlowInEasing
)
)

View file

@ -1,97 +1,54 @@
package it.vfsfitvnm.vimusic.ui.components
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.tween
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
data class TabPosition(
val left: Int,
val width: Int
) {
val center: Int
get() = left + width / 2
}
@Composable
fun TabRow(
tabPagerState: TabPagerState,
modifier: Modifier = Modifier,
content: @Composable () -> Unit
content: @Composable RowScope.() -> Unit
) {
val (colorPalette) = LocalAppearance.current
var tabPositions by remember {
mutableStateOf<List<TabPosition>?>(null)
}
val indicatorWidth by animateIntAsState(
targetValue = (tabPositions?.getOrNull(tabPagerState.transitioningIndex)?.width ?: 0),
tween(
durationMillis = 3000,
easing = FastOutSlowInEasing
)
)
val indicatorStart by animateIntAsState(
targetValue = (tabPositions?.getOrNull(tabPagerState.transitioningIndex)?.left ?: 0),
tween(
durationMillis = 3000,
easing = FastOutSlowInEasing
)
)
Layout(
BoxWithConstraints(
modifier = modifier
.drawBehind {
if (indicatorWidth == 0) return@drawBehind
.fillMaxWidth()
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.drawBehind {
val indicatorWidth = maxWidth.toPx() / tabPagerState.pageCount
drawLine(
color = colorPalette.primaryContainer,
start = Offset(x = indicatorStart + 16.dp.toPx(), y = size.height),
end = Offset(
x = indicatorStart + indicatorWidth - 16.dp.toPx(),
y = size.height
),
cap = StrokeCap.Round,
strokeWidth = 3.dp.toPx()
)
},
content = content
) { measurables, constraints ->
val placeables = measurables.map {
it.measure(constraints)
}
var indicatorStart = tabPagerState.pageIndex * indicatorWidth
if (tabPositions == null) {
var x = 0
val targetPageIndex = tabPagerState.targetPageIndex
tabPositions = placeables.map { placeable ->
TabPosition(
left = x,
width = placeable.width
).also {
x += placeable.width
}
}
}
if (targetPageIndex != null && targetPageIndex != tabPagerState.pageIndex) {
val targetStart = targetPageIndex * indicatorWidth
indicatorStart += (targetStart - indicatorStart) * tabPagerState.progress
}
layout(constraints.maxWidth, placeables.maxOf(Placeable::height)) {
var x = 0
placeables.fastForEach { placeable ->
placeable.place(x = x, y = constraints.minHeight / 2)
x += placeable.width
}
}
drawLine(
color = colorPalette.primaryContainer,
start = Offset(x = indicatorStart + 16.dp.toPx(), y = size.height),
end = Offset(x = indicatorStart + indicatorWidth - 16.dp.toPx(), y = size.height),
cap = StrokeCap.Round,
strokeWidth = 3.dp.toPx()
)
},
content = content,
)
}
}

View file

@ -274,7 +274,7 @@ fun HomeScreen() {
BasicText(
text = text,
style = typography.s.semiBold.color(colorPalette.text),
style = typography.s.semiBold.color(colorPalette.text).center,
modifier = Modifier
.clickable(
indication = rememberRipple(bounded = true),
@ -285,12 +285,13 @@ fun HomeScreen() {
}
}
)
.weight(1f)
.graphicsLayer {
this.alpha = alpha
scaleX = scale
scaleY = scale
}
.padding(horizontal = 16.dp, vertical = 8.dp)
.padding(vertical = 8.dp)
)
}