본문 바로가기
Android/Android Studio

[안드로이드/Kotlin] ViewPager2 + TabLayout 사용

by YOONAYEON 2022. 5. 12.
ViewPager

 

- 한 화면에서 다음 화면으로 전환되는 화면 슬라이드

 

💻 <------
전자제품 전기
ViewPager Adapter data

 

 

✔️ 현재는 FragmentStateAdapter이용하여 프래그먼트 내에서의 뷰페이저 사용에 대해서 알아본다.

 

 

1. 뷰페이저를 사용하고자 하는 Fragment의 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

2. 뷰페이저 안에 담을 각각의 Fragment 만들어 주기

 

class OneFragment: Fragment() {
    lateinit var binding: FragmentOneBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentOneBinding.inflate(inflater, container, false)
        return binding.root
    }
}

 

class TwoFragment: Fragment() {
    lateinit var binding: FragmentTwoBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentTwoBinding.inflate(inflater, container, false)

        return binding.root
    }
}

 

class ThreeFragment: Fragment() {
    lateinit var binding: FragmentThreeBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentThreeBinding.inflate(inflater, container, false)

        return binding.root
    }
}

 

 

3. Adapter 만들기

 

class VPAdapter(fragment: Fragment): FragmentStateAdapter(fragment) {
    
    //여러 개의 프래그먼트를 담아둘 공간
    private val fragList: ArrayList<Fragment> = ArrayList()
    
    //뷰페이저에게 데이터 전달 시, 데이터가 총 몇 개인지 알려주는 함수
    override fun getItemCount(): Int {
        return fragList.size
    }

    //프래그먼트를 생성해주는 함수
    override fun createFragment(position: Int): Fragment {
        return fragList[position]
    }
    
    //처음 실행 시, 아무 값도 없는 fragList에 프래그먼트를 추가해줄 함수
    fun addFragment(fragment: Fragment){
        fragList.add(fragment)
        notifyItemInserted(fragList.size - 1)   //리스트에 새로운 값 추가시 뷰페이저한테 알려야 함
    }

}

 

 

4. 뷰페이저와 어댑터 연결

 

class MainFragment: Fragment() {
    lateinit var binding: FragmentMainBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentMainBinding.inflate(inflater, container, false)

        val testAdapter = VPAdapter(this)
        testAdapter.addFragment(OneFragment())
        testAdapter.addFragment(TwoFragment())
        testAdapter.addFragment(ThreeFragment())

        binding.viewpager.adapter = testAdapter
        binding.viewpager.orientation = ViewPager2.ORIENTATION_HORIZONTAL

        return binding.root
    }
}

 

 

결과 화면

 

 

 

TabLayout

 

- 각 Tab의 item이 클릭되었을 때, 프래그먼트 화면이 바뀌는 위젯

- ViewPager와 함께 사용하면 tab클릭 또는 좌우로 스크롤 시 화면이 바뀜 

- 구현 순서

  1. ViewPager에 Adapter 연결

  2. TabLayout과 ViewPager 연결

  3. 슬라이드 또는 탭 클릭 시 뷰페이저 화면 변경

 

 

 

1. 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toTopOf="@id/viewpager"/>
    
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

2. 그 외의 변환 프래그먼트, 어댑터는 위의 코드 그대로 사용

 

 

3. TabLayout과 ViewPager연결

 

class MainFragment: Fragment() {
    lateinit var binding: FragmentMainBinding
    //추가
    private val info = arrayListOf("tab1", "tab2", "tab3")

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentMainBinding.inflate(inflater, container, false)

        val testAdapter = VPAdapter(this)
        testAdapter.addFragment(OneFragment())
        testAdapter.addFragment(TwoFragment())
        testAdapter.addFragment(ThreeFragment())

        binding.viewpager.adapter = testAdapter
        binding.viewpager.orientation = ViewPager2.ORIENTATION_HORIZONTAL

	//추가
        TabLayoutMediator(binding.tabLayout, binding.viewpager){ //연결할 탭레이아웃과 뷰페이저
            tab, position ->
            tab.text = info[position]		//position에 따른 text지정
        }.attach()				//두 개 연결
        
        return binding.root
    }
}

 

 

4. 탭레이아웃의 인디케이터 디자인 & 텍스트 색상 변경 등은 xml파일의 속성에서 처리

 

 

결과 화면