
인스타그램 스토리를 보다보면 다음 스토리로 넘어갈 때 이렇게 3d박스처럼 넘어가는 모션이 있다! 오늘은 이걸 만들어볼 것이다.
우선은 페이지가 왼쪽일 때랑 오른쪽일 때 회전 방향이 다르기 때문에 현재 드래그하고 있는 방향을 기준으로 해당 페이지가 오른쪽인지, 왼쪽인지를 파악해야 한다.
HorizontalPager(
state = state,
modifier = modifier
.fillMaxSize(),
) { page ->
onDragging(state.isScrollInProgress)
val pageOffset = state.offsetFromCurrentPage(page)
//Page Composable
}
fun PagerState.offsetFromCurrentPage(page: Int) = (currentPage - page) + currentPageOffsetFraction
PagerState에 포함되어 있는 currentPageOffsetFraction를 활용하면 알 수 있는데 현재 페이지가 0이고 왼쪽으로 이동하면 0~0.5로 값이 증가한다. 반대로 오른쪽으로 밀면 0 ~ -0.5로 감소한다.
이 값은 다른 페이지에도 적용이 된다. 내가 왼쪽으로 밀고 있을 때 현재 페이지는 0~0.5로 증가하지만 나의 다음 페이지는 -0.5~0으로 값이 증가하고 있다.
그래서, (currentPage - page)를 더해주면 왼쪽으로 민 페이지는 0~ 0.5가 되다가 왼쪽으로 밀려나면서 1이 되고 오른쪽 페이지는 -1이었다가 점점 증가하면 현재 페이지가 되면 0이 된다.
Box(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
rotationY = pageOffset * -10f
transformOrigin = TransformOrigin(
pivotFractionX = if (pageOffset < 0f) 0f else 1f,
pivotFractionY = 0.5f
)
}
)
roationY값에 pageOffset을 이용해서 회전할 각도를 설정해주었다.
TransformOrigin은 회전하는 축의 위치를 설정해주는 건데 기본값은 x,y축 모두 화면의 한가운데 (0.5f)가 원점이다.
그러나 X의 값을 0으로 옮기면 화면의 왼쪽을 기준으로 회전하고 1로 옮기면 화면의 오른쪽을 기준으로 회전한다.
왼쪽으로 이동할 때는 0을 기준으로 회전하고 오른쪽으로 이동할 때는 1을 기준으로 이동해야 자연스러울테니까~
Box(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
rotationY = pageOffset * -10f
transformOrigin = TransformOrigin(
pivotFractionX = if (pageOffset < 0f) 0f else 1f,
pivotFractionY = 0.5f
)
}
.drawWithContent {
this.drawContent()
drawRect(
Color.Black.copy(
pageOffset.absoluteValue * 0.7f
)
)
}
)
화면이 나가면서 어두워지고 들어오면서 밝아지는 효과를 넣기 위해서 pageOffset을 통해서 위에 Rect을 그려주었다.
https://medium.com/androiddevelopers/customizing-compose-pager-with-fun-indicators-and-transitions-12b3b69af2cc
https://www.sinasamaki.com/pager-animations/