콘텐츠를 왼쪽과 오른쪽 또는 위와 아래로 스크롤하려면 각각 HorizontalPager
및 VerticalPager
컴포저블을 사용하면 됩니다. 이러한 컴포저블은 뷰 시스템의 ViewPager
와 유사한 기능을 갖습니다. 기본적으로 HorizontalPager
는 화면의 전체 너비를 차지하고 VerticalPager
는 전체 높이를 차지하며 페이저는 한 번에 하나의 페이지만 플링합니다. 이러한 기본값은 모두 구성할 수 있습니다.
HorizontalPager
왼쪽과 오른쪽으로 가로 스크롤하는 페이저를 만들려면 HorizontalPager
를 사용하세요.
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
VerticalPager
위아래로 스크롤하는 페이저를 만들려면 VerticalPager
를 사용합니다.
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
지연 생성
HorizontalPager
및 VerticalPager
의 페이지는 필요할 때 지연 컴포지션되고 레이아웃됩니다. 사용자가 페이지를 스크롤하면 컴포저블은 더 이상 필요하지 않은 페이지를 삭제합니다.
화면 밖에 페이지 더 로드
기본적으로 페이저는 화면에 표시되는 페이지만 로드합니다. 화면 밖에 더 많은 페이지를 로드하려면 beyondBoundsPageCount
를 0보다 큰 값으로 설정합니다.
페이저에서 항목으로 스크롤
페이저에서 특정 페이지로 스크롤하려면 rememberPagerState()
를 사용하여 PagerState
객체를 만들고 이를 페이저에 state
매개변수로 전달합니다. 이 상태에서 CoroutineScope
내에서 PagerState#scrollToPage()
를 호출할 수 있습니다.
val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier .fillMaxWidth() .height(100.dp) ) } // scroll to page val coroutineScope = rememberCoroutineScope() Button(onClick = { coroutineScope.launch { // Call scroll to on pagerState pagerState.scrollToPage(5) } }, modifier = Modifier.align(Alignment.BottomCenter)) { Text("Jump to Page 5") }
페이지로 애니메이션을 적용하려면 PagerState#animateScrollToPage()
함수를 사용하세요.
val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier .fillMaxWidth() .height(100.dp) ) } // scroll to page val coroutineScope = rememberCoroutineScope() Button(onClick = { coroutineScope.launch { // Call scroll to on pagerState pagerState.animateScrollToPage(5) } }, modifier = Modifier.align(Alignment.BottomCenter)) { Text("Jump to Page 5") }
페이지 상태 변경에 대한 알림 받기
PagerState
에는 페이지에 관한 정보가 포함된 세 가지 속성(currentPage
, settledPage
, targetPage
)이 있습니다.
currentPage
: 스냅 위치에 가장 가까운 페이지입니다. 기본적으로 스냅 위치는 레이아웃의 시작 부분에 있습니다.settledPage
: 애니메이션이나 스크롤이 실행되지 않는 페이지 번호입니다. 이는currentPage
속성과는 다릅니다.currentPage
는 페이지가 스냅 위치에 충분히 가까우면 즉시 업데이트되지만settledPage
는 모든 애니메이션이 실행을 완료할 때까지 동일하게 유지됩니다.targetPage
: 스크롤 동작의 제안된 중지 위치입니다.
snapshotFlow
함수를 사용하여 이러한 변수의 변경사항을 관찰하고 이에 반응할 수 있습니다. 예를 들어 각 페이지 변경 시 애널리틱스 이벤트를 전송하려면 다음을 실행하면 됩니다.
val pagerState = rememberPagerState(pageCount = { 10 }) LaunchedEffect(pagerState) { // Collect from the a snapshotFlow reading the currentPage snapshotFlow { pagerState.currentPage }.collect { page -> // Do something with each page change, for example: // viewModel.sendPageSelectedEvent(page) Log.d("Page change", "Page changed to $page") } } VerticalPager( state = pagerState, ) { page -> Text(text = "Page: $page") }
페이지 표시기 추가
페이지에 표시기를 추가하려면 PagerState
객체를 사용하여 페이지 중에서 선택된 페이지에 관한 정보를 가져오고 맞춤 표시기를 그립니다.
예를 들어 간단한 원 표시기가 필요한 경우 pagerState.currentPage
를 사용하여 원 수를 반복하고 페이지가 선택되었는지에 따라 원 색상을 변경할 수 있습니다.
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, modifier = Modifier.fillMaxSize() ) { page -> // Our page content Text( text = "Page: $page", ) } Row( Modifier .wrapContentHeight() .fillMaxWidth() .align(Alignment.BottomCenter) .padding(bottom = 8.dp), horizontalArrangement = Arrangement.Center ) { repeat(pagerState.pageCount) { iteration -> val color = if (pagerState.currentPage == iteration) Color.DarkGray else Color.LightGray Box( modifier = Modifier .padding(2.dp) .clip(CircleShape) .background(color) .size(16.dp) ) } }
콘텐츠에 항목 스크롤 효과 적용
일반적인 사용 사례는 스크롤 위치를 사용하여 페이저 항목에 효과를 적용하는 것입니다. 페이지가 현재 선택된 페이지에서 얼마나 떨어져 있는지 확인하려면 PagerState.currentPageOffsetFraction
를 사용하면 됩니다.
그런 다음 선택한 페이지와의 거리를 기준으로 콘텐츠에 변환 효과를 적용할 수 있습니다.
예를 들어 항목이 중심에서 얼마나 떨어져 있는지에 따라 항목의 불투명도를 조정하려면 페이저 내의 항목에서 Modifier.graphicsLayer
를 사용하여 alpha
를 변경합니다.
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager(state = pagerState) { page -> Card( Modifier .size(200.dp) .graphicsLayer { // Calculate the absolute offset for the current page from the // scroll position. We use the absolute value which allows us to mirror // any effects for both directions val pageOffset = ( (pagerState.currentPage - page) + pagerState .currentPageOffsetFraction ).absoluteValue // We animate the alpha, between 50% and 100% alpha = lerp( start = 0.5f, stop = 1f, fraction = 1f - pageOffset.coerceIn(0f, 1f) ) } ) { // Card content } }
맞춤 페이지 크기
기본적으로 HorizontalPager
및 VerticalPager
는 각각 전체 너비 또는 전체 높이를 차지합니다. pageSize
변수를 Fixed
, Fill
(기본값) 또는 맞춤 크기 계산을 갖도록 설정할 수 있습니다.
예를 들어 고정 너비 페이지를 100.dp
로 설정하려면 다음을 실행합니다.
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(100.dp) ) { page -> // page content }
표시 영역 크기를 기준으로 페이지 크기를 조정하려면 맞춤 페이지 크기 계산을 사용하세요. 맞춤 PageSize
객체를 만들고 항목 간의 간격을 고려하여 availableSpace
를 3으로 나눕니다.
private val threePagesPerViewport = object : PageSize { override fun Density.calculateMainAxisPageSize( availableSpace: Int, pageSpacing: Int ): Int { return (availableSpace - 2 * pageSpacing) / 3 } }
콘텐츠 패딩
HorizontalPager
와 VerticalPager
는 모두 콘텐츠 패딩 변경을 지원하므로 페이지의 최대 크기와 정렬에 영향을 줄 수 있습니다.
예를 들어 start
패딩을 설정하면 페이지가 맨 끝에 정렬됩니다.
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(start = 64.dp), ) { page -> // page content }
start
및 end
패딩을 모두 동일한 값으로 설정하면 항목이 가로로 가운데에 정렬됩니다.
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(horizontal = 32.dp), ) { page -> // page content }
end
패딩을 설정하면 페이지가 시작 부분에 정렬됩니다.
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(end = 64.dp), ) { page -> // page content }
top
및 bottom
값을 설정하여 VerticalPager
에 유사한 효과를 줄 수 있습니다. 32.dp
값은 여기서 예시로만 사용됩니다. 각 패딩 크기를 원하는 값으로 설정할 수 있습니다.
스크롤 동작 맞춤설정
기본 HorizontalPager
및 VerticalPager
컴포저블은 스크롤 동작이 페이저에서 작동하는 방식을 지정합니다. 하지만 pagerSnapDistance
또는 flingBehavior
와 같은 기본값은 맞춤설정하고 변경할 수 있습니다.
맞추기 거리
기본적으로 HorizontalPager
및 VerticalPager
는 플링 동작으로 한 번에 스크롤할 수 있는 최대 페이지 수를 1페이지로 설정합니다. 이를 변경하려면 flingBehavior
에서 pagerSnapDistance
를 설정하세요.
val pagerState = rememberPagerState(pageCount = { 10 }) val fling = PagerDefaults.flingBehavior( state = pagerState, pagerSnapDistance = PagerSnapDistance.atMost(10) ) Column(modifier = Modifier.fillMaxSize()) { HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(200.dp), beyondViewportPageCount = 10, flingBehavior = fling ) { PagerSampleItem(page = it) } }
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- Compose의 ConstraintLayout
- 그래픽 수정자
CoordinatorLayout
를 Compose로 이전