Skip to content

Instantly share code, notes, and snippets.

@gold24park
Created August 26, 2023 08:20
Show Gist options
  • Save gold24park/e96e13c113d09ce9df34541e1517d7f0 to your computer and use it in GitHub Desktop.
Save gold24park/e96e13c113d09ce9df34541e1517d7f0 to your computer and use it in GitHub Desktop.
arc_animation_pager
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PageSize
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlin.math.absoluteValue
import kotlin.math.sin
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TestScreen() {
val pageCount = 3
val rotateDegree = 15F
val pagerState = rememberPagerState()
val widthWeight = 0.6F
val configuration = LocalConfiguration.current
val pageSize = PageSize.Fixed(pageSize = (configuration.screenWidthDp * widthWeight).dp)
val horizontalContentPadding = (configuration.screenWidthDp * (1F - widthWeight) / 2).dp
val pageSpacing = 40.dp
HorizontalPager(
modifier = Modifier.fillMaxSize().background(Color.LightGray),
pageCount = pageCount,
state = pagerState,
pageSize = pageSize,
contentPadding = PaddingValues(horizontal = horizontalContentPadding),
pageSpacing = pageSpacing,
) { page ->
Box(
modifier = Modifier.fillMaxSize()
) {
Card(
page = page,
modifier = Modifier
.align(Alignment.Center)
.height(300.dp)
.graphicsLayer {
val pageOffset = pagerState.offsetForPage(page)
rotationZ = -rotateDegree * pageOffset
val distance = (configuration.screenWidthDp.dp / 2) - pageSpacing
val height = sin(Math.toRadians(rotateDegree.toDouble())) * distance.toPx()
translationY = (height * pageOffset.absoluteValue).toFloat()
alpha = lerp(
start = 0.8F,
stop = 1F,
fraction = 1F - pageOffset.absoluteValue.coerceIn(0F, 1F)
)
}
)
}
}
}
@Composable
fun Card(page: Int, modifier: Modifier = Modifier) {
Surface(
modifier = modifier,
color = Color.DarkGray,
shape = RoundedCornerShape(16.dp)
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = "Page $page",
modifier = Modifier.align(Alignment.Center),
style = MaterialTheme.typography.headlineLarge,
color = Color.White
)
}
}
}
@OptIn(ExperimentalFoundationApi::class)
fun PagerState.offsetForPage(page: Int) = (currentPage - page) + currentPageOffsetFraction
fun lerp(start: Float, stop: Float, fraction: Float): Float {
return (1 - fraction) * start + fraction * stop
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment