Add TabRowItem
This commit is contained in:
parent
aa1b495c1e
commit
6deb4bc56e
4 changed files with 113 additions and 87 deletions
|
@ -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(
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue