Bläddra i källkod

Improve TabRow

vfsfitvnm 3 år sedan
förälder
incheckning
4cb2add24e

+ 13 - 2
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/HorizontalTabPager.kt

@@ -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
                 )
             )

+ 34 - 77
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/components/TabRow.kt

@@ -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
-
-                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)
-        }
-
-        if (tabPositions == null) {
-            var x = 0
-
-            tabPositions = placeables.map { placeable ->
-                TabPosition(
-                    left = x,
-                    width = placeable.width
-                ).also {
-                    x += placeable.width
-                }
-            }
-        }
-
-        layout(constraints.maxWidth, placeables.maxOf(Placeable::height)) {
-            var x = 0
-            placeables.fastForEach { placeable ->
-                placeable.place(x = x, y = constraints.minHeight / 2)
-                x += placeable.width
-            }
-        }
+            .fillMaxWidth()
+    ) {
+        Row(
+            verticalAlignment = Alignment.CenterVertically,
+            horizontalArrangement = Arrangement.SpaceBetween,
+            modifier = Modifier
+                .fillMaxWidth()
+                .drawBehind {
+                    val indicatorWidth = maxWidth.toPx() / tabPagerState.pageCount
+
+                    var indicatorStart = tabPagerState.pageIndex * indicatorWidth
+
+                    val targetPageIndex = tabPagerState.targetPageIndex
+
+                    if (targetPageIndex != null && targetPageIndex != tabPagerState.pageIndex) {
+                        val targetStart = targetPageIndex * indicatorWidth
+                        indicatorStart += (targetStart - indicatorStart) * tabPagerState.progress
+                    }
+
+                    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,
+        )
     }
 }
 

+ 3 - 2
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt

@@ -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)
                             )
                         }