본문 바로가기
🖥 Programming/📱 Android (Kotlin)

[kotlin] ViewPager2 + TabLayout 스와이프 뷰 만들기

by MinChan-Youn 2022. 7. 6.

안녕하세요~ 챠니입니다! :)

 

오늘은 ViewPager2 + TabLayout를 활용하여 스와아프 뷰(Swipe View)를 만드는 방법에 대해서 알아보겠습니다.

 

1. gradle 설정

먼저 필요한 ViewBinding 및 viewpager2를 dependencies에 추가합니다.

추가하는 코드는 주석설명을 달아놓았습니다.

 

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.example.viewpager2_tablayout_kotlin"
        minSdk 23
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    //====== ViewBinding 설정
    buildFeatures{
        viewBinding true
        dataBinding true
    }
}

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.2'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    //====== ViewPager2
    implementation 'androidx.viewpager2:viewpager2:1.0.0'
}

 

 

 

2. 레이아웃

Main Layout(메인레이아웃) 구성도 입니다.

아래쪽에는 TabLayout이 위쪽에는 ViewPager2를 배치하였습니다.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp_viewpager_main"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/tl_navigation_view"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tl_navigation_view"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

3. 프래그먼트(Fragment) 생성

ViewPager2안에 들어갈 Fragment를 만들어줍니다.

각 Fragment는 ViewBinding을 활용하여 Binding합니다.

 

[Tab1]

// Tab1Fragment.kt

class Tab1Fragment : Fragment() {
    private var _binding: FragmentTab1Binding? = null
    private val binding get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View? {
        _binding = FragmentTab1Binding.inflate(inflater, container, false)
        return binding.root
    }
    
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#80FF0000"
    tools:context=".Tab1Fragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Hello Fragment1!!"
        android:textColor="@color/white"
        android:textSize="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

[Tab2]

// Tab2Fragment.kt
class Tab2Fragment : Fragment() {
    private var _binding: FragmentTab2Binding? = null
    private val binding get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View? {
        _binding = FragmentTab2Binding.inflate(inflater, container, false)
        return binding.root
    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#8000FF00"
    tools:context=".Tab1Fragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Hello Fragment2!!"
        android:textColor="@color/white"
        android:textSize="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

[Tab3]

// Tab3Fragment.kt
class Tab3Fragment : Fragment() {
    private var _binding: FragmentTab3Binding? = null
    private val binding get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View? {
        _binding = FragmentTab3Binding.inflate(inflater, container, false)
        return binding.root
    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#800000FF"
    tools:context=".Tab1Fragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Hello Fragment3!!"
        android:textColor="@color/white"
        android:textSize="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

4. ViewPager2Adapter 및 연결

다음은 ViewPager2 Adapter를 생성하여 ViewPager2에 연결 및 컴파일을 해보겠습니다.

 

아래는 MainActivity 코드입니다.

//MainActivity.kt
class MainActivity : AppCompatActivity() {
    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initViewPager()
    }

    private fun initViewPager() {
        //ViewPager2 Adapter 셋팅
        var viewPager2Adatper = ViewPager2Adapter(this)
        viewPager2Adatper.addFragment(Tab1Fragment())
        viewPager2Adatper.addFragment(Tab2Fragment())
        viewPager2Adatper.addFragment(Tab3Fragment())

        //Adapter 연결
        binding.vpViewpagerMain.apply {
            adapter = viewPager2Adatper

            registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
                override fun onPageSelected(position: Int) {
                    super.onPageSelected(position)
                }
            })
        }

        //ViewPager, TabLayout 연결
        TabLayoutMediator(binding.tlNavigationView, binding.vpViewpagerMain) { tab, position ->
            Log.e("YMC", "ViewPager position: ${position}")
            when (position) {
                0 -> tab.text = "Tab1"
                1 -> tab.text = "Tab2"
                2 -> tab.text = "Tab3"
            }
        }.attach()
    }
}

 

 

아래는 ViewPager2 Adapter코드입니다.

//ViewPager2Adapter.kt
class ViewPager2Adapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) {
    var fragments: ArrayList<Fragment> = ArrayList()

    override fun getItemCount(): Int {
        return fragments.size
    }

    override fun createFragment(position: Int): Fragment {
        return fragments[position]
    }

    fun addFragment(fragment: Fragment) {
        fragments.add(fragment)
        notifyItemInserted(fragments.size - 1)
        //TODO: notifyItemInserted!!
    }

    fun removeFragement() {
        fragments.removeLast()
        notifyItemRemoved(fragments.size)
        //TODO: notifyItemRemoved!!
    }

}

 

 

5. 결과물

다음은 ViewPager2 Adapter를 생성하여 ViewPager2에 연결 및 컴파일을 해보곘습니다.

코드에 문제가 없다면 다음과 같은 결과물을 얻을 수 있습니다.

 

 

 

 

 

 

 

 

 

글 정리 & 소스코드

[소스코드]
ViewPager2+TabLayout: 

https://github.com/younminchan/kotlin-study/tree/main/ViewPager2_TabLayout_kotlin

 

GitHub - younminchan/kotlin-study: kotlin 다양한 예제코드

kotlin 다양한 예제코드. Contribute to younminchan/kotlin-study development by creating an account on GitHub.

github.com

 

 

 

질문 또는 궁굼한 부분은 댓글을 남겨주세요! 친절하게 답변드리겠습니다!

응원의 댓글은 저에게 큰 힘이 된답니다! :)

즐거운 하루되세요!

 

깃허브 보러 놀러오세요 👇 (맞팔환영)

https://github.com/younminchan

 

younminchan - Overview

안드로이드 2년차 개발자 •⚽️/🎤/🥁/🖥/🏃‍♂️/🚴‍♂️/🤟 TechBlog⬇️ minchanyoun.tistory.com - younminchan

github.com