Compose로 뷰페이저 구현하기

seunghee song·2024년 2월 13일

Compose

목록 보기
1/1
post-thumbnail

xml에서는 viewpager을 구현하려면 어댑터도 구현해야하고 디자인 레이아웃도 따로 디자인해야하고....굉장히 귀찮았다.

그런데 컴포즈를 이용해 탭간 이동을 구현하는 방법은 생각보다 간단했다!

본 영상을 참고해서 구현하였다.
참고한 영상

탭으로 이동하는 화면을 만들기 위해서는 크게 TabRow() 밑에 HorizontalPager을 구현하면 된다.

1단계

enum class MyTab(val title:String) {
    HOME("홈"),
    PROFILE("프로필"),
    LIST("리스트"),
    SETTING("설정")
}

정의할 탭들을 enum class로 만들어 준다.

2단계

val scope = rememberCoroutineScope()
val pagerState = rememberPagerState(pageCount = {MyTab.values().size})
val selectedTabIndex = remember{ derivedStateOf { pagerState.currentPage }  }

구현하기 앞서 이 3가지 변수를 정의해주어야한다.

  • rememberCoroutineScope: 비동기 작업을 실행할 때 사용하는 것이다. HorizontalPager사용시 비동기 처리를 통해 페이지를 변경하여 사용자에게 정보를 제공해야하므로 정의하였다.

  • rememberPagerState(): HorizontalPager의 상태를 관리하는 객체를 생성하고 기억한다. 이 상태에서는 페이지 인덱스, 스크롤 위치, 페이지 수 등의 정보를 포함할 수 있다. 이것으로 현재 보이는 페이지를 추적하고 사용자가 스와이프시 페이지 변경을 해야할때 필요한 정보를 제공한다.

  • selectedTabIndex: HorizontalPager의 페이지 인덱스를 나타내는 상태이다. 사용자가 페이지를 스와이프하여 변경하면 동기화하여 현재 위치한 페이지 인덱스를 표시할 수 있다.

3단계

TabRow(
                selectedTabIndex = selectedTabIndex.value,
                modifier = Modifier.fillMaxWidth()
                ) {
                MyTab.values().forEachIndexed{index, currentTab->
                    Tab(
                        selected = selectedTabIndex.value == index,
                        selectedContentColor = Color.Yellow,
                        unselectedContentColor = Color.DarkGray,
                        onClick = {
                            scope.launch {
                                
                                pagerState.animateScrollToPage(currentTab.ordinal)
                            }
                        },
                        text = {Text(text = currentTab.title)}
                    )
                }
            }

TabRow를 정의한다.
이 컨테이너는 탭들을 수평으로 배열하는 기능을 한다.
selectedTabIndex는 현재 선택된 탭의 이니덱스를 전달하며 어떤 탭이 활성화 상태인지를 표시한다. 또한 forEachIndexed는 탭과 해당 인덱스를 반복 처리한다.
onClick 을 통해 탭을 클릭했을 때 실행할 로직을 정의한다. 여기서는 scope.launch를 통해 코루틴을 시작하고
pagerState.animateScrollToPage(currentTab.ordinal) 를 호출해 해당 탭에 해당하는 페이지로 스무스하게 스크롤한다.
currentTab.ordinal 은 currentTab이 enum 클래스에 정의된 순서를 반환한다. 이는 뒤에 있을 HorizontalPager에서 연동하는데 사용된다.

4단계

HorizontalPager(
                state = pagerState,
                modifier = Modifier
                    .fillMaxWidth()
                    .weight(1f)
            ) {
                Box(
                    modifier = Modifier.fillMaxSize(),
                    contentAlignment = Alignment.Center
                ){
                    Text(text = MyTab.values().get(selectedTabIndex.value).title)
                }
            }

HorizontalPager를 정의하여 스와이프 가능한 페이지를 정의한다. 이때 같은 selectedTabIndex 변수를 사용해 tabRow와 연동되는 페이지를 만들 수 있다.

❗️추가 커스텀❗️
탭을 누를 때마다 ripple 현상이 발생해 Tab의 매개변수 중 interactionSource를 null로 정의해주었다.
(구글은 왜 항상 디폴트로 ripple을 넣을까 모르겠다...)

interactionSource = null,

탭 할때마다 움직이는 바의 색상도 커스텀하기 위해 초록색으로 정의해주었다.

contentColor = Color.Green
profile
안드로이드 개발자

0개의 댓글