한 화면에서 여러 뷰를 스와핑해서 전환하는 기능이 필요할 때 사용한다. 여기서 페이지란 여러 뷰가 될 수도 있고 프래그먼트가 될 수 도 있다.
💡 잠깐!!
RecyclerView도 이런 데이터를 리스트로 표현하는 것인데 뭐가 다른거지?
ViewPager 와 RecyclerView 는 데이터를 리스트로 표현하고 이들을 스와핑할 수 있다는 점에서 비슷한 기능을 가지고 있다.
하지만 ViewPager는 한번에 하나의 데이터만 보여줄 수 있는(미리보기 기능이 존재하긴 하는데 우선 완벽히 공존을 안된다) 반면 RecyclerViewsms 한번에 보여줄 수 있는 데이터 수에는 제한이 없다.
즉, ViewPager는 여러 데이터를 하나씩 애니메이션을 주면서 스와핑 하는데 특화되어 있다.
Viewpager | ViewPager2 |
---|---|
좌우 스크롤 | 좌우 상하 스크롤 |
FragmentStatePagerAdapter | FragmentStateAdapter |
PagerAdapter | RecyclerView.Adapter |
addPageChangeListener() | registerOnpageCallback() |
이 외에도 여러 리스너가 변경되고 추가되었고 애니메이션이 좀더 향상 되었다.
간단히 화면 두 개를 좌우로 스와핑하는 화면을 만들어보자!!
(gif)
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/mono4"
app:layout_constraintBottom_toTopOf="@+id/rg_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_weight="10" />
<RadioGroup
android:id="@+id/rg_navigation"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/viewPager"
app:layout_constraintVertical_weight="1" >
<RadioButton
android:id="@+id/rb_a"
android:layout_weight="1"
android:layout_width="0dp"
android:background="@drawable/radiobutton"
android:button="@null"
android:text="A"
android:gravity="center"
android:textColor="@color/mono8"
android:fontFamily="@font/semi_bold"
android:layout_height="match_parent"/>
<RadioButton
android:id="@+id/rb_b"
android:layout_weight="1"
android:layout_width="0dp"
android:text="B"
android:gravity="center"
android:textColor="@color/mono8"
android:fontFamily="@font/semi_bold"
android:background="@drawable/radiobutton"
android:button="@null"
android:layout_height="match_parent"/>
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
class TestViewPageAdapter(fragment: FragmentActivity) : FragmentStateAdapter(fragment) {
private val pageList = mutableListOf<Fragment>()
override fun getItemCount(): Int {
return pageList.size
}
override fun createFragment(position: Int): Fragment {
return pageList[position]
}
fun addFragment(newFragment: Fragment) { pageList.add(newFragment) }
}
data class Navigation(
val name: String,
val newInstance: (()-> Fragment),
val radioButtonId: Int
)
val naviList = mutableListOf<Navigation>()
naviList.add(Navigation("A", { AFragment.newInstance() }, R.id.rb_a))
naviList.add(Navigation("B", { BFragment.newInstance() }, R.id.rb_b))
binding.viewPager.apply {
adapter = TestViewPageAdapter(this@TestActivity).apply {
naviList.forEach{ addFragment(it.newInstance()) }
}
}
binding.rgNavigation.apply {
// init check
check(naviList.first().radioButtonId)
setOnCheckedChangeListener { _, id ->
// 클릭된 index 찾기
val index = naviList.indices.find {
naviList[it].radioButtonId == id
} ?: 0
// 이동할 fragment로 page 이동
// smoothScroll이 true 면 정말 스무시하게 페이지 전환이 된고 false 면 애니메이션 없이 띡띡 페이지 이동한다.
binding.viewPager.setCurrentItem(index, true)
}
}
Radio Group 으로 Bottom Navigation 느낌을 나도록 그려보았다.
Bottom Navigation View 를 사용해도 되지만 좀 더 완벽히 커스텀? 하기 위해 ? RadioButton 으로 구성된 Radio Group으로 구현해봤다. 원하는 뷰를 다 그릴 수 있을 것 같다.
하지만 라디오 개수에 따라 뷰를 다시 그리고 지워야할 번거로움이 있으므로 커스텀뷰를 만들어 개수, border, buttonStyle, checkListener 등 으로 조작이 가능하면 좋겠다는 생각이 있다. 근데 우선 이 글은ViewPager2를 위한 글이니 여기까지 한다.
이 ViewPager를 통해서 광고를 보여주는 듯 하고 미리보기? 기능도 존재하고 애니메이션도 세부 설정이 가능해보인다. 이 추가 기능들은 새 글을 만들어서 작성해볼 예정이다.