뷰 페이저는 스와이프 이벤트로 화면을 전환할 때 사용한다. 플레이 스토어 앱을 보면 사용자가 손가락을 이용해 화면을 양옆으로 밀어 이전이나 다음 화면을 볼 수 있다. 이러한 기능이 뷰 페이저이다.
뷰 페이저는 플랫폼 API에서 제공하지 않기 때문에 androidx 라이브러리를 이용해 개발해야한다. 이러한 뷰 페이저는 2019년 뷰 페이저 2가 릴리즈 되었고, 더 유용한 기능을 많이 제공하기 때문에 이를 많이 쓴다.
뷰 페이저를 쓰기 위해 의존성을 추가하자
implementation 'androidx.viewpager2:viewpager2:1.0.0'
그리고 메인 레이아웃에 뷰 페이저를 담을 공간 android:id="@+id/viewpager"
과 뷰 페이저에 표시될 항목을 담을 레이아웃 android:id="@+id/itemPagerTextView"
을 작성하자. 이런 패턴은 리사이클러 뷰에서 썼던 방식과 동일하다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="5"
android:text="BUTTON"
android:textSize="50sp"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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">
<TextView
android:id="@+id/itemPagerTextView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/white"
tools:text="hello"
android:textSize="40sp" />
</LinearLayout>
뷰 페이저2는 화면을 항목으로 본다. 각 항목이 순서대로 나열되어 있는데 단지 한 화면에 항목이 하나가 나온다는 개념이다. 따라서 리사이클러 뷰에서 살펴봤던 어댑터를 적용해야한다. 뷰 페이저2에 사용할 수 있는 어댑터는 2가지인데 리사이클러 뷰에서 봤던 RecyclerView.Adapter 를 그대로 이용하거나 FragmentStateAdapter 를 사용할 수 있다.
리사이클러 뷰 어댑터를 이용하는 것은 이전 포스팅에서 사용하던 방법과 큰 차이가 없다. 단지 뷰 페이저2의 어댑터로 적용만 하면 된다. 즉, 당연히 뷰 홀더도 만들어 줘야 한다.
class MyPagerViewHolder(val binding: ItemPagerBinding) : RecyclerView.ViewHolder(binding.root)
class MyPagerAdapter(val datas: MutableList<String>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount(): Int = datas.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = MyPagerViewHolder(
ItemPagerBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val binding = (holder as MyPagerViewHolder).binding
binding.itemPagerTextView.text = datas[position]
when (position % 3) {
0 -> binding.itemPagerTextView.setBackgroundColor(Color.RED)
1 -> binding.itemPagerTextView.setBackgroundColor(Color.BLUE)
2 -> binding.itemPagerTextView.setBackgroundColor(Color.GREEN)
}
}
}
그리고 mainActivity 코드를 다음과 같이 작성하면 된다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val datas = mutableListOf<String>()
for (i in 1..10) {
datas.add("item $i")
}
binding.viewpager.adapter = MyPagerAdapter(datas)
}
}
콘텐츠 영역의 윗 영역을 위로 스와이프하면 다음 화면이 나타나고, 밑의 button 은 그대로 유지된다.
위와 같이 리사이클러 뷰 어댑터를 이용해서 뷰 페이저2를 구현한 수도 있지만 대부분 각 항목(화면)은 복잡하게 작성된다. 따라서 각 항목의 내용은 프래그먼트로(따라서 액티비티와 같이) 작성한다.
만약 항목을 프레그먼트로 작성했으면 FragmentStateAdapter 로 뷰 페이저2를 구현한다. 각각의 프래그먼트 레이아웃과 클래스가 이미 준비되어있다고 보고 아래의 코드를 보자.
class MyFragmentPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
val fragments : List<Fragment>
init {
fragments = listOf(OneFragment(), TwoFragment(), ThreeFragment())
}
override fun getItemCount() = fragments.size
override fun createFragment(position: Int): Fragment = fragments[position]
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.viewpager.adapter = MyFragmentPagerAdapter(this)
//binding.viewpager.orientation = ViewPager2.ORIENTATION_VERTICAL 스와이프 방향 변경
}
}
해당 액티비티에서는 스와이프할 때마다 다른 프레그먼트들이 나타난다.