Add TabRowItem

This commit is contained in:
vfsfitvnm 2022-07-16 20:04:47 +02:00
parent aa1b495c1e
commit 6deb4bc56e
4 changed files with 113 additions and 87 deletions

View file

@ -15,6 +15,7 @@ import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.input.pointer.util.addPointerInputChange
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlin.math.absoluteValue
@ -22,7 +23,8 @@ import kotlin.math.absoluteValue
@Stable
class TabPagerState(
pageIndexState: MutableState<Int>,
val pageCount: Int
val pageCount: Int,
val coroutineScope: CoroutineScope
) {
var pageIndex by pageIndexState
@ -47,46 +49,54 @@ class TabPagerState(
animatable.updateBounds(lowerBound, upperBound)
}
suspend fun animateScrollTo(newPageIndex: Int) {
tempPageIndex = newPageIndex
if (newPageIndex > pageIndex) {
animatable.animateTo(
animatable.upperBound!!, tween(
durationMillis = 300,
easing = FastOutSlowInEasing
fun animateScrollTo(newPageIndex: Int) {
coroutineScope.launch {
tempPageIndex = newPageIndex
if (newPageIndex > pageIndex) {
animatable.animateTo(
animatable.upperBound!!, tween(
durationMillis = 300,
easing = FastOutSlowInEasing
)
)
)
} else if (newPageIndex < pageIndex) {
animatable.animateTo(
animatable.lowerBound!!, tween(
durationMillis = 300,
easing = FastOutSlowInEasing
} else if (newPageIndex < pageIndex) {
animatable.animateTo(
animatable.lowerBound!!, tween(
durationMillis = 300,
easing = FastOutSlowInEasing
)
)
)
}
}
pageIndex = newPageIndex
animatable.snapTo(0f)
tempPageIndex = null
pageIndex = newPageIndex
animatable.snapTo(0f)
tempPageIndex = null
}
}
}
@Composable
fun rememberTabPagerState(pageIndexState: MutableState<Int>, pageCount: Int): TabPagerState {
return remember {
val coroutineScope = rememberCoroutineScope()
return remember(coroutineScope) {
TabPagerState(
pageIndexState = pageIndexState,
pageCount = pageCount,
coroutineScope = coroutineScope
)
}
}
@Composable
fun rememberTabPagerState(initialPageIndex: Int, pageCount: Int): TabPagerState {
val coroutineScope = rememberCoroutineScope()
return remember {
TabPagerState(
pageIndexState = mutableStateOf(initialPageIndex),
pageCount = pageCount
pageCount = pageCount,
coroutineScope = coroutineScope
)
}
}
@ -98,8 +108,6 @@ fun HorizontalTabPager(
modifier: Modifier = Modifier,
content: @Composable (index: Int) -> Unit
) {
val coroutineScope = rememberCoroutineScope()
val itemProvider = remember(state) {
object : LazyLayoutItemProvider {
override val itemCount = state.pageCount
@ -120,7 +128,7 @@ fun HorizontalTabPager(
detectHorizontalDragGestures(
onHorizontalDrag = { change, dragAmount ->
velocityTracker.addPointerInputChange(change)
coroutineScope.launch {
state.coroutineScope.launch {
state.animatable.snapTo(state.offset - dragAmount)
}
},
@ -131,7 +139,7 @@ fun HorizontalTabPager(
velocityTracker.resetTracking()
coroutineScope.launch {
state.coroutineScope.launch {
val isEnough = initialTargetValue.absoluteValue > size.width / 2
if (initialTargetValue > 0) {
state.animatable.animateTo(

View file

@ -1,14 +1,25 @@
package it.vfsfitvnm.vimusic.ui.components
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicText
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
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.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.center
import it.vfsfitvnm.vimusic.utils.color
import it.vfsfitvnm.vimusic.utils.semiBold
@Composable
fun TabRow(
@ -47,10 +58,55 @@ fun TabRow(
strokeWidth = 3.dp.toPx()
)
},
content = content,
content = content
)
}
}
@Composable
fun RowScope.TabRowItem(
tabPagerState: TabPagerState,
index: Int,
text: String,
) {
val (colorPalette, typography) = LocalAppearance.current
val alpha by animateFloatAsState(
if (tabPagerState.transitioningIndex == index) {
1f
} else {
0.4f
}
)
val scale by animateFloatAsState(
if (tabPagerState.transitioningIndex == index) {
1f
} else {
0.9f
}
)
BasicText(
text = text,
style = typography.s.semiBold.color(colorPalette.text).center,
modifier = Modifier
.clickable(
indication = rememberRipple(bounded = true),
interactionSource = remember { MutableInteractionSource() },
onClick = {
tabPagerState.animateScrollTo(index)
}
)
.weight(1f)
.graphicsLayer {
this.alpha = alpha
scaleX = scale
scaleY = scale
}
.padding(vertical = 8.dp)
)
}
inline val TabPagerState.transitioningIndex: Int
get() = tempPageIndex ?: pageIndex

View file

@ -2,7 +2,6 @@ package it.vfsfitvnm.vimusic.ui.screens
import android.net.Uri
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@ -54,7 +53,6 @@ import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
@ExperimentalFoundationApi
@ -138,7 +136,6 @@ fun HomeScreen() {
pageCount = 4
)
val coroutineScope = rememberCoroutineScope()
val density = LocalDensity.current
var topAppBarOffset by remember {
@ -171,7 +168,6 @@ fun HomeScreen() {
.coerceIn(minimumValue = (-52).dp, maximumValue = 0.dp)
return Offset.Zero
}
}
}
@ -189,13 +185,21 @@ fun HomeScreen() {
drawCircle(
color = colorPalette.primaryContainer,
center = size.center.copy(x = 8.dp.toPx()),
radius = 16.dp.toPx()
radius = 16.dp.toPx(),
shadow = Shadow(
color = colorPalette.primaryContainer,
blurRadius = 4.dp.toPx()
)
)
drawCircle(
color = colorPalette.primaryContainer,
center = Offset(x = 32.dp.toPx(), y = 0f),
radius = 8.dp.toPx()
radius = 8.dp.toPx(),
shadow = Shadow(
color = colorPalette.primaryContainer,
blurRadius = 4.dp.toPx()
)
)
}
.padding(horizontal = 16.dp)
@ -257,66 +261,26 @@ fun HomeScreen() {
.padding(top = 52.dp + topAppBarOffset)
) {
TabRow(tabPagerState = tabPagerState) {
@Composable
fun Item(
index: Int,
text: String
) {
val alpha by animateFloatAsState(
if (tabPagerState.transitioningIndex == index) {
1f
} else {
0.4f
}
)
val scale by animateFloatAsState(
if (tabPagerState.transitioningIndex == index) {
1f
} else {
0.9f
}
)
BasicText(
text = text,
style = typography.s.semiBold.color(colorPalette.text).center,
modifier = Modifier
.clickable(
indication = rememberRipple(bounded = true),
interactionSource = remember { MutableInteractionSource() },
onClick = {
coroutineScope.launch {
tabPagerState.animateScrollTo(index)
}
}
)
.weight(1f)
.graphicsLayer {
this.alpha = alpha
scaleX = scale
scaleY = scale
}
.padding(vertical = 8.dp)
)
}
Item(
TabRowItem(
tabPagerState = tabPagerState,
index = 0,
text = "Songs"
)
Item(
TabRowItem(
tabPagerState = tabPagerState,
index = 1,
text = "Playlists"
)
Item(
TabRowItem(
tabPagerState = tabPagerState,
index = 2,
text = "Artists"
)
Item(
TabRowItem(
tabPagerState = tabPagerState,
index = 3,
text = "Albums"
)

View file

@ -120,13 +120,11 @@ fun PlayerBottomSheet(
indication = rememberRipple(bounded = true),
interactionSource = remember { MutableInteractionSource() },
onClick = {
coroutineScope.launch(Dispatchers.Main) {
layoutState.expand()
if (layoutState.isCollapsed) {
tabPagerState.pageIndex = pageIndex
} else {
tabPagerState.animateScrollTo(pageIndex)
}
layoutState.expand()
if (layoutState.isCollapsed) {
tabPagerState.pageIndex = pageIndex
} else {
tabPagerState.animateScrollTo(pageIndex)
}
}
)