본문 바로가기
깡샘 코틀린

12-2 탭 레이아웃 - 탭 버튼 구성

by 농농씨 2023. 6. 30.

탭 레이아웃은 탭(tab)으로 구분하는 화면에서 탭 버튼을 배치하는 레이아웃이다. 탭 버튼을 다양하게 표시하고자 사용하는 뷰이다.

 

구글 플레이 스토어를 들어가보면 탭이 적으면 그냥 나열되는데 탭이 많으면 옆으로 스크롤 해서 볼 수 있다.

탭 버튼이 많으면 이처럼 스크롤되게 제공해야 한다. 탭버튼을 가로등분으로 제공할수도 있다. 이런 설정들을 탭 레이아웃을 통해 출력한다.

// 탭 레이아웃 등록
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
    androdi:layout_height="match_parent"
    android:orientation="vertical">
    <com.google.android.material.tabs.TabLayout // 탭 레이아웃 선언
    	android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <FrameLayout // FrameLayout 선언
    	android:id="@+id/tabContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

위 코드는 탭 화면을 만드는 레이아웃 XML 파일이다. TabLayout과 FrameLayout을 선언했다. 사용자가 TabLayout으로 구성한 탭 버튼을 선택하면 FrameLayout 위치에 탭의 내용을 출력한다.

 

// 코드에서 탭 버튼 정의
val tab1: TabLayout.Tab = tabLayout.newTab() // 탭 버튼 객체 생성
tab1.text="Tab1"
tabLayout.addTab(tab1) // 탭 레이아웃에 탭 버튼 추가

val tab2: TabLayout.Tab = tabLayout.newTab()
tab2.text="Tab2"
tabLayout.addTab(tab2)

val tab3: TabLayout.Tab = tabLayout.newTab()
tab3.text="Tab3"
tabLayout.addTab(tab3)

탭 레이아웃에 추가되는 탭 버튼은 TabLayout.newTab() 함수로 만들어지는 TabLayout.Tab 객체이며 이 객체의 text 속성으로 문자열을, icon 속성으로 이미지를 지정한다. 그리고 이 Tab 객체를 TabLayout.addTab() 함수의 매개변수로 지정하여 탭 버튼을 추가한다.

 

위 코드는 TabLayout에 Tab 객체를 3개 추가했으므로 탭 버튼이 3개인 탭 화면을 만든다. 그런데 만약 탭 레이아웃의 탭 버튼을 동적으로 만들 필요가 없다면 앞의 예처럼 탭 버튼을 코드에서 정의하지 않고 레이아웃 XML 파일의 TabItem으로 정의해도 된다. TabLayout 하위에 추가되는 TabItem 하나가 탭 버튼 하나를 의미한다.

// XML 파일에서 탭 버튼 정의
<com.google.android.material.tabs.TabLayout // 탭 레이아웃 선언
    android:id="@id/tabs"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <com.google.android.material.tabs.TabItem // TabItem으로 레이아웃 파일에서 탭 정의
    	android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tab1" />
    <com.google.android.material.tabs.TabItem
    	android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tab2" />
    <com.google.android.material.tabs.TabItem
    	android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Tab3" />
</com.google.android.material.tabs.TabLayout>

 

사용자가 탭 버튼을 선택할 때 출력해야 하는 내용은 코드에서 탭 버튼의 이벤트 핸들러에 명시해야 한다.

// 탭 버튼 이벤트 처리
tabLayout.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener {
    // 탭 버튼을 선택할 때 이벤트
    override fun onTabSelected(tab: TabLayout.Tab?) {
    // onTabSelected가 이벤트 처리?
    	val transaction = supportfragmentmanager.beginTransaction()
        when (tab?.text) {
            "Tab1"-> transaction.replace(R.id.tabContent,OneFragment())
            "Tab2"-> transaction.replace(R.id.tabContent,TwoFragment())
            "Tab3"-> transaction.replace(R.id.tabContent,ThreeFragment())
        }
        transaction.commit()
    }
    // 선택된 탭 버튼을 다시 선택할 때 이벤트
    override fun onTabReselected(tab: TabLayout.Tab?) {
    	(... 생략 ...)
    }
    // 다른 탭 버튼을 눌러 선택된 탭 버튼이 해제될 때 이벤트
    override fun onTabunselected(tab: TabLayout.Tab?) {
    	(... 생략 ...)
    }
})

TabLayout을 이용해 탭 버튼 3개를 출력한 예이다. 탭 레이아웃은 기본으로 탭 버튼을 가로등분으로 배치한다. 그러므로 3개의 버튼이 가로 3등분으로 출력된다.

TabLayout의 addOnTabSelectedListener() 함수를 이용해 이벤트 핸들러 객체를 지정해 준다. 탭 버튼 이벤트 핸들러 객체는 TabLayout.OnTabSelectedListener를 구현한 객체여야 하며이벤트 콜백 함수의 매개변수현재 이벤트가 발생한 Tab 객체이다.

탭 레이아웃은 다음과 같은 속성으로 탭 버튼을 다양하게 출력할 수 있다.

 

탭 버튼 정렬하기

tabGravity는 탭 버튼을 정렬하는 속성이다. 기본값은 fill 이며 탭 버튼을 가로로 등분하여 배치한다. center는 탭 버튼을 가운데 정렬한다.

 

스크롤 설정하기

tabMode 속성은 탭 버튼을 스크롤할 수 있는지를 설정한다. 기본값은 fixed인데 스크롤을 지원하지 않는다는 의미이다. 만약 scrollable로 설정하면 탭 버튼이 왼쪽부터 나열되고 모두 출력할 수 없다면 자동으로 가로 스크롤이 생긴다.

 

뷰 페이저 연동하기

탭 레이아웃으로 탭 화면을 만들면서 11장에서 살펴본 뷰 페이저와 연동할 수 있다. 탭 레이아웃과 뷰 페이저는 화면을 여러 장 제공하는 용도이므로 둘을 연동하는 일이 많다. 예를 들어 Facebook 화면은 탭버튼을 눌러 화면을 전환할 수도 있지만 탭 버튼 아래 콘텐츠 부분을 뷰 페이저로 제공하여 스와이프로 화면을 전환하게 할 수도 있다. 이처럼 탭 레이아웃은 뷰 페이저와 연동을 지원한다.

// 탭 레이아웃과 뷰 페이저 등록
<LinearLayout xmlns:android="hattp://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">
    <com.google.android.material.tabs.TabLayout // 탭 레이아웃 선언
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable">
    </com.google.android.material.tabs.TabLayout>
    <androidx.viewpager2.widget.ViewPager2 // 뷰 페이저2 등록
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

레이아웃 XML 파일에 TabLayout과 ViewPager2를 등록한 후 코드에서 TabLayoutMediator를 이용해 둘을 연동하면 된다.

// 탭 레이아웃과 뷰 페이저 연동
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
	tab.text = "Tab${(position + 1)}"
}.attach()

TabLayoutMediator 생성자의 매개변수로 연동하고자 하는 탭 레이아웃뷰 페이저 객체를 전달한다. 이렇게 하면 뷰 페이저의 화면이 3개이면 탭 버튼도 자동으로 3개가 나온다. 또한 사용자가 탭 버튼을 누르는 순간 뷰 페이저 화면이 자동으로 조정되며, 반대로 사용자가 뷰 페이저 화면을 넘기는 순간 탭 버튼도 자동으로 조정된다. 이처럼 뷰 페이저와 연동하면 탭 버튼의 문자열3번째 매개변수로 전달하는 함수에서 지정할 수 있다. 이 함수의 매개변수는 탭 버튼 객체(tab)와 화면에서 위치(position)이므로 이를 이용해 탭 버튼의 문자열 등을 지정하면 된다.