Android Jetpack Compose UI/Compose UIs

[Jetpack Compose] ViewPager Tab Layout에 연결하기 : 스와이프해 탭 바꾸도록 만들기

반응형

Tab과 ViewPager은 언제 사용되는가?

Swipe해서 탭이 바뀌는 UI는 많은 앱에 쓰이며, 여러 페이지를 탭으로 구성해 사용 복잡도를 줄이기 위해 사용한다. 

 

그림1. Tab + Viewpager

 

그림1과 같은 동작으로 Tab을 직접 클릭해서 Page를 이동할 수도 있으며, Swipe 동작을 통해 페이지를 이동할 수도 있다. 오늘은 이러한 UI를 만드는 방법에 대해 알아보고자 한다.

 

위 페이지를 만들기 위해서는 다음 단계들을 거쳐야 한다.

  1. Tab + ViewPager 만들기 위한 라이브러리 추가하기
  2. Tab 목록 만들기
  3. PagerState 선언하기
  4. CoroutineScope 선언하기
  5. TabRow 만들기
  6. HorizontalPager 만들기

 

 

Compose로 Tab과 ViewPager 만들기

1. Tab + ViewPager 만들기 위한 라이브러리 추가하기

accompanist에서 Tab과 Viewpager을 만드는 라이브러리를 제공하는데 아래 두가지 라이브러리를 앱 수준의 build.gradle에 추가해야 한다.

implementation "com.google.accompanist:accompanist-pager:0.20.1"
implementation "com.google.accompanist:accompanist-pager-indicators:0.20.1"

 

2. Tab 목록 만들기

먼저 Tab 목록을 만들어야 한다. 탭에 표시할 제목들을 다음과 같이 작성한다.

val pages = listOf("페이지1", "페이지2", "페이지3")

 

3. PagerState 선언하기

다음은 TabRow과 Pager 객체에서 공유할 데이터인 PagerState 객체를 만들어야 한다.

val pagerState = rememberPagerState()

PagerState 객체는 TabRow와 Pager객체 모두에서 사용하는 객체로 현재 몇 페이지에 있는지를 저장한다.

 

 

4. CoroutineScope 선언하기

Composable에서 페이지를 이동하는 동작은 CoroutineScope에서 수행되어야 한다. 따라서 다음과 같이 Composable 내부에서 사용할 CoroutineScope을 선언해야 한다.

val coroutineScope = rememberCoroutineScope()

 

 

5. TabRow 만들기

 

그림2. TabRow

 

다음은 TabRow를 만들어야 한다. TabRow는 그림2와 같이 Tab들을 저장하는 Row 객체이다.

 

TabRow에 2에서 선언한 pages 변수의 title들을 Tab 객체를 넣어야 하며, pagerState를 연결시켜야 한다.

TabRow(
    selectedTabIndex = pagerState.currentPage,
    indicator = { tabPositions ->
        TabRowDefaults.Indicator(
            Modifier.pagerTabIndicatorOffset(pagerState, tabPositions)
        )
    }
) {
    pages.forEachIndexed { index, title ->
        Tab(
            text = { Text(text = title) },
            selected = pagerState.currentPage == index,
            onClick = {
                coroutineScope.launch {
                    pagerState.scrollToPage(index)
                }
            }
        )
    }
}

또한 탭이 클릭되었을 때 4에서 선언한 coroutineScope를 사용해 pagerState.scrollToPage 함수를 수행해야 한다.

 

 

 

6. HorizontalPager 만들기

HorizontalPager에도 2, 3에서 만든 pages와 pagerState를 다음과 같이 연결시킨다.

HorizontalPager(
    count = pages.size,
    state = pagerState,
) { page ->
    Text(
        modifier = Modifier.wrapContentSize(),
        text = page.toString(),
        textAlign = TextAlign.Center,
        fontSize = 30.sp
    )
}

 

 

완성 화면

위와 같이 만들면 다음과 같은 페이지가 완성된다.

그림3. 완성된 Tab, ViewPager

 

전체 코드

전체 코드는 다음과 같다.

val pages = listOf("페이지1", "페이지2", "페이지3")

@AndroidEntryPoint
class TabPagerActivity : ComponentActivity() {
    @OptIn(ExperimentalPagerApi::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NewTheme {
                Surface(
                    modifier = Modifier
                        .fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    Column(
                        modifier = Modifier.fillMaxSize(),
                        verticalArrangement = Arrangement.Center
                    ) {
                        val pagerState = rememberPagerState()
                        val coroutineScope = rememberCoroutineScope()

                        TabRow(
                            selectedTabIndex = pagerState.currentPage,
                            indicator = { tabPositions ->
                                TabRowDefaults.Indicator(
                                    Modifier.pagerTabIndicatorOffset(pagerState, tabPositions)
                                )
                            }
                        ) {
                            pages.forEachIndexed { index, title ->
                                Tab(
                                    text = { Text(text = title) },
                                    selected = pagerState.currentPage == index,
                                    onClick = {
                                        coroutineScope.launch {
                                            pagerState.scrollToPage(index)
                                        }
                                    }
                                )
                            }
                        }

                        HorizontalPager(
                            count = pages.size,
                            state = pagerState,
                        ) { page ->
                            Text(
                                modifier = Modifier.wrapContentSize(),
                                text = page.toString(),
                                textAlign = TextAlign.Center,
                                fontSize = 30.sp
                            )
                        }
                    }
                }
            }
        }
    }
}
반응형

 

이 글의 저작권은 Kotlin World 에 있습니다. 글, 이미지 무단 재배포 및 변경을 금지합니다.