Created
January 21, 2025 11:49
-
-
Save junsuk5/c35b58f221ca182cd1b4965b2e3abbed to your computer and use it in GitHub Desktop.
PageCurlDemo.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun BookPageFlip() { | |
var offsetX by remember { mutableStateOf(0f) } | |
var currentPage by remember { mutableStateOf(0) } | |
val animatedOffset = animateFloatAsState( | |
targetValue = offsetX, | |
animationSpec = spring( | |
dampingRatio = 0.8f, | |
stiffness = Spring.StiffnessLow | |
) | |
) | |
Box( | |
modifier = Modifier | |
.fillMaxSize() | |
.pointerInput(Unit) { | |
detectDragGestures( | |
onDragEnd = { | |
// 드래그가 끝났을 때 페이지 전환 여부 결정 | |
val threshold = size.width * 0.4f | |
if (abs(offsetX) > threshold) { | |
if (offsetX > 0 && currentPage > 0) { | |
currentPage-- | |
} else if (offsetX < 0) { | |
currentPage++ | |
} | |
} | |
offsetX = 0f | |
}, | |
onDrag = { change, dragAmount -> | |
change.consume() | |
offsetX += dragAmount.x | |
} | |
) | |
} | |
) { | |
// 현재 페이지 | |
Box( | |
modifier = Modifier | |
.fillMaxSize() | |
.graphicsLayer { | |
val pageRotation = (offsetX / size.width) * 180f | |
rotationY = pageRotation | |
cameraDistance = 12f * density | |
} | |
) { | |
BookPage(currentPage) | |
} | |
// 다음/이전 페이지 (뒷면) | |
Box( | |
modifier = Modifier | |
.fillMaxSize() | |
.graphicsLayer { | |
val pageRotation = ((offsetX / size.width) * 180f) + 180f | |
rotationY = pageRotation | |
cameraDistance = 12f * density | |
} | |
) { | |
if (offsetX > 0 && currentPage > 0) { | |
BookPage(currentPage - 1) | |
} else if (offsetX < 0) { | |
BookPage(currentPage + 1) | |
} | |
} | |
} | |
} | |
@Composable | |
fun BookPage(pageNumber: Int) { | |
Box( | |
modifier = Modifier | |
.fillMaxSize() | |
.background(Color.White) | |
.shadow(8.dp) | |
) { | |
// 페이지 내용 | |
Column( | |
modifier = Modifier | |
.fillMaxSize() | |
.padding(16.dp) | |
) { | |
Text( | |
text = "Page ${pageNumber + 1}", | |
style = MaterialTheme.typography.bodyLarge, | |
modifier = Modifier.padding(bottom = 16.dp) | |
) | |
Text( | |
text = "Lorem ipsum dolor sit amet...", | |
style = MaterialTheme.typography.bodyMedium | |
) | |
} | |
} | |
} | |
// 페이지 그림자 효과 | |
@Composable | |
fun PageShadow(progress: Float) { | |
Box( | |
modifier = Modifier | |
.fillMaxHeight() | |
.width(8.dp) | |
.background( | |
brush = Brush.horizontalGradient( | |
colors = listOf( | |
Color.Black.copy(alpha = 0.2f * (1 - progress)), | |
Color.Transparent | |
) | |
) | |
) | |
) | |
} | |
// 사용 예시 | |
@Preview(showBackground = true) | |
@Composable | |
fun BookReader() { | |
Surface( | |
modifier = Modifier.fillMaxSize().systemBarsPadding(), | |
color = Color.White | |
) { | |
BookPageFlip() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment