Kotlin

[android : kotlin] 코틀린 프레그먼트(Fragment)를 사용한 뷰페이저2(ViewPager2) 사용 예제 (FragmentStateAdapter)

뷰페이저2(ViewPager2)는 스크린 화면을 좌우로 스와이프(swipe)를 통해 컨텐츠 전환을 할 수 있는 컨테이너 이다. 뷰페이저(ViewPager2)는 데이터를 페이지 단위로 표시한다. 뷰페이저는 뷰그룹(ViewGroup)으로 부터 상속된다. 프레그먼트(Fragment)를 사용하여 뷰페이저2를 생성하려면 FragmentStateAdapter()를 사용한다. registerOnPageChangeCallback()를 사용하여 뷰가 전환될 때 이벤트 처리를 할 수 있다.

 

뷰페이저2를 사용하려면 build.gradle(:app)파일에 라이브러리를 추가해주어야한다.

implementation ‘androidx.viewpager2:viewpager2:1.0.0’

 

제일 먼저 페이지로 사용할 프레그먼트 레이아웃을 추가하자. 클래스 파일과 레이아웃 xml파일을 동시에 만들어보자 

왼쪽 Project탭에서 java폴더 아래 본인이 만든 패키지명을 클릭후 마우스 오른쪽 버튼을 눌러 NEW > Fragment > 본인에게 필요한 프레그먼트를 선택한다. 아무겂도 없는 빈 프레그먼트 레이아웃을 선택하였다.


프레그먼트 이름과 개발한 언어를 선택 후 Finish버튼을 클릭하면 완료된다.


동일한 생성방법으로 3개의 프레그먼트를 준비하였다.

[MyFragment1.kt]

package edu.kotlin.study

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

class MyFragment1 : Fragment() {
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_my1, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment MyFragment1.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            MyFragment1().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

 

[fragment_my1.xml]

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyFragment1">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="1st blank_fragment" />

</FrameLayout>

[MyFragment2.kt]

package edu.kotlin.study

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [MyFragment2.newInstance] factory method to
 * create an instance of this fragment.
 */
class MyFragment2 : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_my2, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment MyFragment2.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            MyFragment2().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

[fragment_my2.xml]

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyFragment2">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

[MyFragment3.kt]

package edu.kotlin.study

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [MyFragment3.newInstance] factory method to
 * create an instance of this fragment.
 */
class MyFragment3 : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_my3, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment MyFragment3.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            MyFragment3().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

[fragment_my3.xml]

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyFragment3">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="3rd blank_fragment" />

</FrameLayout>

FragmentStateAdapter를 상속받아서 MyFragmentPagerAdapter클래스를 생성하였다. 오버라이드해야할 메서드는 getItemCount()와 createFragment() 등 2개이다. createFragment메서드안에서 처리해야할 것은 position값을 받아서 원하는 프레그먼트 레이아웃을 호출 하는 것이다.

 

[MainActivity.kt]

package edu.kotlin.study

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import kotlinx.android.synthetic.main.activity_main.*

private const val NUM_PAGES = 3

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val mAdapter = MyFragmentPagerAdapter(FragmentActivity())

        //어댑터 적용
        viewPager1.adapter = mAdapter


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

                textView1.text = "$position 페이지"
                super.onPageSelected(position)
            }
        })

    }

    inner class MyFragmentPagerAdapter(fm: FragmentActivity) : FragmentStateAdapter(fm) {
        override fun getItemCount(): Int {
            return NUM_PAGES
        }

        override fun createFragment(position: Int): Fragment {
            val idx = position
            return when (idx) {
                0 -> {
                    MyFragment1()
                }
                1 -> {
                    MyFragment2()
                }
                else -> {
                    MyFragment3()
                }
            }
        }

    }

}

[activity_main.xml]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
    android:id="@+id/textView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:text="텍스트뷰"
    android:textAppearance="@style/TextAppearance.AppCompat.Display2" />


    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

    </androidx.viewpager2.widget.ViewPager2>


</LinearLayout>

[build.gradle(:app)]

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29

    defaultConfig {
        applicationId "edu.kotlin.study"
        minSdkVersion 22
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.1'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    implementation 'androidx.viewpager2:viewpager2:1.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}

[REFERENCE]

ViewPager2로 프래그먼트 간 슬라이드 – Android Developers

ViewPager2 Releases – Android Developers

ViewPager2 Reference – Android Developers

 

Leave a Reply

error: Content is protected !!