티스토리 뷰
이번 포스팅에서는 기존 XML
에서 ViewPager
의 기능을 Compose
로 유사하게 구현하는 방법에 대하여 알아보겠습니다.
시작하기 전에 다음의 내용을 build.gradle(:app)
에 추가해 주세요
implementation "com.google.accompanist:accompanist-pager:0.20.1"
implementation "com.google.accompanist:accompanist-pager-indicators:0.20.1"
1) 기본 사용 방법
Compose
에서는 방향에 따라서 HorizontalPager
와 VerticalPager
로 사용합니다.
val colorList = listOf(
Color(0xFFFF1744),
Color(0xFF651FFF),
Color(0xFF2979FF)
)
Column(modifier = Modifier.fillMaxSize()) {
HorizontalPager(
count = colorList.size,
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) { page ->
Box(
modifier = Modifier
.fillMaxSize()
.background(colorList[page]),
contentAlignment = Alignment.Center
) {
Text(
text = "Horizontal Pager: $page",
color = Color.White,
fontWeight = FontWeight.Bold
)
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(10.dp)
.background(Color.White)
)
VerticalPager(
count = colorList.size,
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) { page ->
Box(
modifier = Modifier
.fillMaxSize()
.background(colorList[page]),
contentAlignment = Alignment.Center
) {
Text(
text = "Vertical Pager: $page",
color = Color.White,
fontWeight = FontWeight.Bold
)
}
}
}
사용 방법은 count
에 반복 횟수를 넣어주고, content
에서 표시할 UI
를 구현해 주면 됩니다.
content
에서는 해당 포지션의 값(Int
)을 받을 수 있습니다.
2) contentPadding
Column(modifier = Modifier.fillMaxSize()) {
HorizontalPager(
count = colorList.size,
contentPadding = PaddingValues(horizontal = 100.dp),
modifier = Modifier
.fillMaxWidth()
.fillMaxSize(0.5f)
) { page ->
...
}
}
contentPadding
으로 내부의 padding
값을 주면 위의 이미지처럼 Pager
의 아이템이 시작하기 전 여백이나, 스크롤 시 다음 아이템이 보이도록 설정이 가능합니다.
3) Scroll Effect
HorizontalPager(
count = colorList.size,
contentPadding = PaddingValues(horizontal = 100.dp),
modifier = Modifier
.fillMaxWidth()
.fillMaxSize(0.5f)
) { page ->
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.graphicsLayer {
val pageOffset = calculateCurrentOffsetForPage(page).absoluteValue
// 크기 조절
lerp(
start = 0.85f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
).also { scale ->
scaleX = scale
scaleY = scale
}
// 투명도 조절
alpha = lerp(
start = 0.2f,
stop = 1f,
fraction = 1f - pageOffset.coerceIn(0f, 1f)
)
}
.fillMaxSize()
.background(colorList[page])
) {
...
}
}
graphicsLayer
을 이용하여 스크롤 시 아이템의 투명도, 크기의 값을 변경할 수 있습니다.
lerp
의 값을 변경해가며 구현하고자 하는 디자인의 효과를 구현해 주시면 됩니다.
주의할 점은 graphicsLayer
의 위치에 따라 UI
반영이 달라질 수 있으니 유의해 주세요
ex) fillMaxSize
와 background
를 graphicsLayer
이전에 설정하면 다른 결과가 나옵니다.
4) Indicator
val state = rememberPagerState()
HorizontalPager(
count = colorList.size,
state = state,
contentPadding = PaddingValues(horizontal = 100.dp),
modifier = Modifier
.fillMaxWidth()
.fillMaxSize(0.5f)
) { page ->
...
}
HorizontalPagerIndicator(
pagerState = state,
modifier = Modifier
.padding(top = 20.dp)
.align(Alignment.CenterHorizontally)
)
rememberPagerState
를 이용하여 변수 생성 후 Pager
의 state
에 값을 넣어줍니다.
그 후 HorizontalPagerIndicator
/ VerticalPagerIndicator
에 만든 state
를 넣어주면 Indicator
의 설정이 끝납니다.
PagerIndicator
는 모양, 크기, 선택된 Indicator
색상, 선택되지 않은 Indicator
색상, Indicator
의 간격을 설정할 수 있습니다.
5) Tab + Pager
val state = rememberPagerState()
val scope = rememberCoroutineScope()
Column(modifier = Modifier.fillMaxSize()) {
TabRow(
selectedTabIndex = state.currentPage,
indicator = { tabPositions ->
TabRowDefaults.Indicator(
Modifier.pagerTabIndicatorOffset(state, tabPositions)
)
}
) {
tabList.forEachIndexed { index, title ->
Tab(
text = { Text(title) },
selected = state.currentPage == index,
onClick = {
scope.launch {
state.animateScrollToPage(index)
}
},
)
}
}
HorizontalPager(
count = colorList.size,
state = state,
contentPadding = PaddingValues(horizontal = 100.dp),
modifier = Modifier
.fillMaxWidth()
.fillMaxSize(0.5f)
) { page ->
...
}
}
Tab
과 Pager
를 연결시키는 코드는 아래의 코드입니다.
indicator = { tabPositions ->
TabRowDefaults.Indicator(
Modifier.pagerTabIndicatorOffset(state, tabPositions)
)
}
연결을 시킨 뒤 Tab
의 아이템을 클릭 시에 Pager
의 포지션을 이동시켜 주어야 합니다.
scope.launch {
state.animateScrollToPage(index)
}
Compose
에서 Pager
를 이동시키는 animateScrollToPage
은 Coroutine
으로 함수이기 때문에 CoroutineScope
를 생성 후 사용하여야 합니다.
6) Auto Scroll
LaunchedEffect(state.currentPage) {
delay(1000)
val index = (state.currentPage + 1) % state.pageCount
state.animateScrollToPage(index)
}
Compose
에서 자동 스크롤은 간단하게 구현이 가능합니다.
LaunchedEffect
를 통해서 Pager
의 currentPage
의 값이 변경되면 animateScrollToPage
를 움직이게 됩니다.
LaunchedEffect
는 이미 CoroutineScope
를 가지고 있기 때문에 별도의 CoroutineScope
가 필요하지 않습니다.
delay
시간 동안 수동으로 스크롤을 하면 이전 Coroutine
은 Cancel
되고 다시 생성하므로 스크롤이 끝난 시점부터 delay
가 다시 작동하게 됩니다.
'안드로이드 > 코드' 카테고리의 다른 글
Compose GraphicsLayer (0) | 2022.09.02 |
---|---|
Compose 기초 4 : Gradient (0) | 2022.09.01 |
Compose Animation (2) | 2022.08.27 |
포켓몬 도감 만들기(3) : Fast Api, Compose, 상세 화면 (0) | 2022.08.21 |
포켓몬 도감 만들기(2) : Fast Api, Compose, 홈 화면, 리스트 화면 (0) | 2022.08.21 |
- Total
- Today
- Yesterday
- 포켓몬 도감
- Duplicate class found error
- Compose Naver Map
- Android
- Compose MotionLayout
- Compose QRCode Scanner
- Compose BottomSheet
- column
- Compose ModalBottomSheetLayout
- Worker
- Compose ConstraintLayout
- WebView
- compose
- Compose BottomSheetScaffold
- 웹뷰
- 안드로이드 구글 지도
- 안드로이드
- Fast api
- LazyColumn
- Compose 네이버 지도
- Compose 네이버 지도 api
- Pokedex
- Retrofit
- Row
- Compose BottomSheetDialog
- Gradient
- Kotlin
- WorkManager
- Duplicate class fond 에러
- Android Compose
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |