implementation("androidx.viewpager2:viewpager2:1.0.0") 는 할 필요가 없다. 기본적으로 뷰페이저2 들어있음. 디자인탭에서 꺼내쓰면 됨.
먼저 레이아웃을 짠다. 메인에 툴바, 탭레이아웃, 뷰페이저2 놓는다.
그리고 뷰페이저2에 들어갈 프래그먼트 두 개 만든다.
(여기에서는 투두리스트랑 북마크리스트. 일단 리스트는 안만듦. 프래그먼트에 텍뷰만.)
뷰페이저 어댑터를 만들어야 한다. FragmentStateAdapter를 상속받는데, 매개변수로 FragmentActivity가 올 수도 있고, Fragment가 올 수도 있다. 뷰페이저2가 액티비티 안에 있으면 어댑터가 FragmentActivity를 매개변수로 받아 넘기고, 프래그먼트 안에 있으면 Fragment를 받아서 넘긴다. (AppCompatActivity는 FragmentActivity를 상속받는다)
어댑터에서는 각 탭에 들어갈 프래그먼트들을 리스트로 들고 있는데, 각 프래그먼트의 제목도 함께 들고있으려면(탭레이아웃에 띄우기 위함) 데이터클래스를 만들어서 프래그먼트와 제목을 갖게 하고, 이 데이터클래스를 리스트로 들고 있으면 된다.
FragmentStateAdapter를 상속받으면 getItemCount랑 createFragment를 구현하라고 에러가 뜬다. 리스트의 사이즈랑, 포지션의 프래그먼트를 반환해주면 된다.
이외에 getFragment, getTitle, getTodoListFragment 등 필요한 메서드를 만들면 된다.
이제 메인을 작성해준다.
먼저 뷰페이저에 어댑터를 넣어준다. (어댑터 변수는 lazy로 선언해둠)
뷰페이저에 registerOnPageChangeCallback 해준다. 이 메서드는 파라미터로 OnPageChangeCallback 추상클래스?를 받으므로 object : OnPageChangeCallback() {...} 을 인자로 넣어준다. onPageScrolled, onPageSelected, onPageScrollStateChanged 함수를 오버라이드 할 수 있으니 필요에 따라 추가한다.
(예제에서는 선택된 페이지가 투두리스트 프래그먼트인지에 따라서 플로팅액션버튼을 show(), hide() 해줬다.)
뷰페이저2와 탭레이아웃을 연결하는 건 TabLayoutMediator 으로 한다.
나중에 손을 좀 봐야겠지만, 일단 뷰페이저 적용 코드를 정리해보자.
/*
메인 레이아웃은 툴바, 탭레이아웃, 뷰페이저2, 플로팅 버튼을 둔다.
(툴바, 플로팅 버튼은 선택사항)
*/
// viewpager2 패키지, TodoMainActivity 추가
// activity_todo_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=".TodoMainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:title="TODO LIST" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="52dp">
<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.TabLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</androidx.viewpager2.widget.ViewPager2>
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_create_todo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_input_add"
android:contentDescription="할일 추가 버튼"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
/*
프래그먼트 두 개는 구현 안하고 텍뷰만 띄워서 프래그먼트 표시.
*/
// 페이저 어댑터
class TodoMainViewPagerAdapter(fragmentActivity: FragmentActivity) :
FragmentStateAdapter(fragmentActivity) {
private val fragments = listOf(
TodoMainTab(TodoListFragment.newInstance(), R.string.main_tab_todo_title),
TodoMainTab(BookmarkListFragment.newInstance(), R.string.main_tab_bookmark_title),
)
override fun getItemCount(): Int = fragments.size
override fun createFragment(position: Int): Fragment = fragments[position].fragment
fun getFragment(position: Int): Fragment = fragments[position].fragment
fun getTitle(position: Int): Int = fragments[position].title
fun getTodoListFragment(): Fragment? = fragments.find {
it.fragment::class.java == TodoListFragment::class.java
}?.fragment
// fun getFragment(clazz: Class<out Fragment>): Fragment? =
// fragments.find { it.fragment::class.java == clazz }?.fragment
}
// TodoMainTab 데이터 클래스 (어댑터의 프래그먼트를 제목이랑 같이 관리하기 위함)
data class TodoMainTab(
val fragment: Fragment,
@StringRes val title: Int
)
/*
어댑터에 들어갈 프래그먼트 2개. TodoListFragment, BookmarkListFragment.
각 프래그먼트에는 텍뷰 하나 넣어서 표시.
*/
class TodoListFragment : Fragment() {
companion object {
@JvmStatic
fun newInstance() = TodoListFragment()
}
private var _binding: FragmentTodoListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentTodoListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
class BookmarkListFragment : Fragment() {
companion object {
@JvmStatic
fun newInstance() = BookmarkListFragment()
}
private var _binding: FragmentBookmarkListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentBookmarkListBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
/*
R.string.main_tab_todo_title == TODO
R.string.main_tab_bookmark_title == BOOKMARK
*/
// 액티비티
private val viewPagerAdapter by lazy { TodoMainViewPagerAdapter(this) }
private fun initView(ac: AppCompatActivity) = binding.apply {
viewPager.adapter = viewPagerAdapter
// object : ViewPager2.OnPageChangeCallback() 일수도?
viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (viewPagerAdapter.getFragment(position) is TodoListFragment)
fabCreateTodo.show()
else fabCreateTodo.hide()
}
})
// TabLayout x ViewPager2
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.setText(viewPagerAdapter.getTitle(position))
}.attach()
// // fab
// fabCreateTodo.setOnClickListener {
// createTodoLauncher.launch(
// TodoContentActivity.newIntent(this@TodoMainActivity)
// )
// }
}