이 튜토리얼에서는 Kotlin을 사용하여 안드로이드 앱에서 탭 레이아웃(TabLayout)을 구현하는 방법을 단계별로 살펴봅니다. TabLayout과 ViewPager를 연동하면 스와이프로 화면을 전환할 수 있는 직관적인 탭 UI를 손쉽게 만들 수 있습니다.
구현 순서 한눈에 보기
전체 과정은 다음 6단계로 진행됩니다.
- 새 프로젝트 생성
- 메인 레이아웃(activity_main.xml) 작성
- MainActivity.kt에서 TabLayout과 ViewPager 연결
- 어댑터(MyAdapter.kt) 클래스 작성
- 탭별 프래그먼트 3개 생성
- AndroidManifest.xml 확인 후 앱 실행
1단계 — 새 프로젝트 만들기
Android Studio에서 File → New Project를 선택하고, 빈 프로젝트(Empty Activity) 템플릿으로 새 프로젝트를 생성합니다. 언어는 Kotlin으로 지정하세요.
2단계 — 메인 레이아웃 작성
res/layout/activity_main.xml 파일에 아래 코드를 추가합니다. 상단에는 TabLayout, 하단에는 ViewPager를 배치합니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#1db995">
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tabLayout"
android:layout_centerInParent="true"
android:layout_marginTop="100dp"
tools:layout_editor_absoluteX="8dp" />
</RelativeLayout>3단계 — MainActivity.kt 작성
src/MainActivity.kt 파일에 아래 코드를 추가합니다. 여기서는 탭 3개(Football, Cricket, NBA)를 동적으로 추가하고, 탭 선택 이벤트와 ViewPager 페이지 변경 이벤트를 서로 연동합니다.
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.google.android.material.tabs.TabLayout.TabLayoutOnPageChangeListener
class MainActivity : AppCompatActivity() {
lateinit var tabLayout: TabLayout
lateinit var viewPager: ViewPager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = "KotlinApp"
tabLayout = findViewById(R.id.tabLayout)
viewPager = findViewById(R.id.viewPager)
tabLayout.addTab(tabLayout.newTab().setText("Football"))
tabLayout.addTab(tabLayout.newTab().setText("Cricket"))
tabLayout.addTab(tabLayout.newTab().setText("NBA"))
tabLayout.tabGravity = TabLayout.GRAVITY_FILL
val adapter = MyAdapter(this, supportFragmentManager,
tabLayout.tabCount)
viewPager.adapter = adapter
viewPager.addOnPageChangeListener(TabLayoutOnPageChangeListener(tabLayout))
tabLayout.addOnTabSelectedListener(object : OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
viewPager.currentItem = tab.position
}
override fun onTabUnselected(tab: TabLayout.Tab) {}
override fun onTabReselected(tab: TabLayout.Tab) {}
})
}
}4단계 — 어댑터 클래스 작성
새 Kotlin 클래스 파일 MyAdapter.kt를 만들고 아래 코드를 추가합니다. 이 어댑터는 탭 위치(position)에 따라 해당 프래그먼트를 반환하는 역할을 합니다.
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
@Suppress("DEPRECATION")
internal class MyAdapter(
var context: Context,
fm: FragmentManager,
var totalTabs: Int
) : FragmentPagerAdapter(fm) {
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> {
Football()
}
1 -> {
Cricket()
}
2 -> {
NBA()
}
else -> getItem(position)
}
}
override fun getCount(): Int {
return totalTabs
}
}5단계 — 프래그먼트 3개 생성
각 탭에 표시될 프래그먼트 3개(Cricket, Football, NBA)를 생성합니다. 이름은 프로젝트 성격에 맞게 자유롭게 변경할 수 있습니다.
Cricket.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class Cricket : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// 이 프래그먼트의 레이아웃을 인플레이트합니다
return inflater.inflate(R.layout.fragment_cricket, container, false)
}
}fragment_cricket.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Cricket">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Cricket Fragment"
android:textAlignment="center"
android:textSize="16sp"
android:textStyle="bold" />
</FrameLayout>Football.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class Football : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// 이 프래그먼트의 레이아웃을 인플레이트합니다
return inflater.inflate(R.layout.fragment_football, container, false)
}
}fragment_football.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Football">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Football Fragment"
android:textAlignment="center"
android:textSize="16sp"
android:textStyle="bold" />
</FrameLayout>NBA.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
class NBA : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// 이 프래그먼트의 레이아웃을 인플레이트합니다
return inflater.inflate(R.layout.fragment_n_b_a, container, false)
}
}fragment_n_b_a.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NBA">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="NBA Fragment"
android:textAlignment="center"
android:textSize="16sp"
android:textStyle="bold" />
</FrameLayout>6단계 — AndroidManifest.xml 설정
AndroidManifest.xml 파일에 아래와 같이 MainActivity가 등록되어 있는지 확인합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.q11">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>앱 실행 및 결과 확인
이제 애플리케이션을 실행해 보겠습니다. 실제 안드로이드 기기를 컴퓨터에 연결했다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤, 툴바의 Run(실행) 아이콘
을 클릭하세요. 실행 대상 목록에서 본인의 모바일 기기를 선택하면, 기기 화면에 아래와 같은 결과가 표시됩니다.



마무리 및 참고 사항
위 예제처럼 TabLayout과 ViewPager를 함께 사용하면 탭을 누르거나 화면을 좌우로 스와이프할 때 자동으로 페이지가 전환되는 UI를 쉽게 구현할 수 있습니다. 참고로 TabLayout은 머티리얼 디자인 라이브러리에 포함되어 있으므로, build.gradle(app)에 com.google.android.material:material 의존성이 추가되어 있는지 반드시 확인하세요. 또한 최신 프로젝트에서는 FragmentPagerAdapter 대신 FragmentStateAdapter(ViewPager2용) 사용을 권장하며, 이 경우 마이그레이션 가이드를 참고하면 좋습니다.