ViewPager2 (FragmentStateAdapter 이용)

두리두두·2024년 5월 6일

Android

목록 보기
13/25
  • 지난 포스팅에서 뷰페이저2를 RecyclerViewAdapter로 구현해보았다.
  • RecyclerView에서는 하나의 item_list.xml을 가지고 재사용을 해서, 동일한 형태의 화면을 보여주는 것이었다면. 프래그먼트를 사용할 때는 보여줄 화면을 각각 프래그먼트로 만든다.
  • 탭레이아웃을 함께 활용해보겠다

구현

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">
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Monday" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Tuesday" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Wednesday" />
        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Wednesday" />
    </com.google.android.material.tabs.TabLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager_idol"
        android:layout_width="0dp"
        android:layout_height="680dp"
        app:layout_constraintTop_toBottomOf="@id/tabLayout"
        app:layout_constraintStart_toStartOf="parent"
        android:orientation="horizontal"/>

</androidx.constraintlayout.widget.ConstraintLayout>

FragmentA.xml ~ FragmentD.xml

  • 프래그먼트 4개를 만들 것이다. 안드로이드스튜디오에서 프래그먼트로 생성하면 클래스명과 매칭되는 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=".FragmentA">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment1" />
    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/idol1"
        android:visibility="visible"/>
</FrameLayout>

FragmentStateAdapter.kt

  • RecyclerView에서의 어답터와 다르게 인자로 프래그먼트를 넘겨줘야한다.
class FragmentAdapter(fragmentList: FragmentActivity) :
    FragmentStateAdapter(fragmentList)
{
    var fragments = listOf<Fragment>()

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

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

}

MainActivity.kt

  • 프래그먼트 어답터에 프래그먼트들을 붙이고,
  • 만들어진 프래그먼트 어답터를 뷰페이저 뷰에 적용한다.
// 프래그먼트 어답터에 프래그먼트들을 넣어준다.
val fragmentList = listOf(FragmentA(),FragmentB(),FragmentC(),FragmentD())

val fragmentAdapter = FragmentAdapter(this)
fragmentAdapter.fragments = fragmentList

// 뷰페이저에 어답터를 붙인다.
viewPargerFragment = findViewById<ViewPager2>(R.id.viewPager_idol)
viewPargerFragment.adapter = fragmentAdapter
  • 그리고 탭레이아웃에 각 프래그먼트를 적용한다.
val tabLayout = findViewById<TabLayout>(R.id.tabLayout)
// 탭레이아웃 설정
val tabTitles = listOf("Profile","Search","MyPage","ETC")
// val tabIcons = listOf(R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4)
val iconList = ArrayList<Drawable?>()
iconList.add(ContextCompat.getDrawable(this, R.drawable.image1))
iconList.add(ContextCompat.getDrawable(this, R.drawable.image2))
iconList.add(ContextCompat.getDrawable(this, R.drawable.image3))
iconList.add(ContextCompat.getDrawable(this, R.drawable.image4))

// 탭 레이아웃과 뷰페이저 연결해야 탭따라서 움직임
TabLayoutMediator(tabLayout, viewPargerFragment) {tab, position ->
            tab.text = tabTitles[position]
            tab.icon = iconList[position]
        }.attach()

TabLayout

  • 여러개의 버튼이 있고, 각 버튼마다 activity나 fragment를 보여준다.
  • 원래는 각 탭 버튼을 클릭했을 때 onClickListner로 행동을 지정한다. 본 글에서는 뷰페이저와 함께 사용했으므로 뷰페이저의 슬라이딩이 적용되어 페이지를 넘겨도 탭이 넘어가고, 탭을 클릭해도 슬라이딩으로 페이지가 넘어간다.
    (addOnTabSelectedListener)
  • 탭 선택 시 프래그먼트 이동으로 처리하는 법
        tabLayout.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener {

            // 탭 버튼을 선택할 때 이벤트
            override fun onTabSelected(tab: TabLayout.Tab?) {
                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 onTabUnselected(tab: TabLayout.Tab?) {
                TODO("Not yet implemented")
            }
            
            // 선택된 탭 버튼을 다시 선택할 때 이벤
            override fun onTabReselected(tab: TabLayout.Tab?) {
                TODO("Not yet implemented")
            }
        })
    }

TabLayoutMeditator

  • TabLayout과 ViewPager2를 연결해주는 객체이다.
  • 탭이 선택될 때 ViewPager2의 위치를 선택한 탭과 동기화하고, 스와이프를 할 때 TabLayout의 위치를 스와이프된 위치와 동기화한다.
// 탭 레이아웃과 뷰페이저 연결해야 탭따라서 움직임
TabLayoutMediator(tabLayout, viewPargerFragment) {tab, position ->
            tab.text = tabTitles[position]
            tab.icon = iconList[position]
        }.attach()

결과

  • 탭을 위에 두고 아이콘과 메뉴명을 지정했다. 아이콘은 큰 이미지라 그런지 안나온다 쩝..
  • 탭을 넘기거나 이미지를 슬라이딩할 때마다 각 프래그먼트가 보인다.

업로드중..

profile
야금야금 앱 개발자

0개의 댓글