ViewPager
swipe 뷰를 사용하면 손가락의 가로 동작이나 스와이프로 탭과 같은 동위 화면 간을 탐색할 수 있습니다.
이러한 탐색 패턴을 가로 페이징이라고도 합니다.
구성요소
1. Viewpager
- 각각의 페이지(Pagefragment)를 보여줄 view에 해당하며, 각 페이지들이 표시될 activity 또는 fragment 내에 선언된다.
2. PagerAdapter
- 각 페이지들을 설정하고 순서 및 기본적인 셋팅(데이터)을 하여 viewPager에게 pageFragment를 제공한다.
3. PageFragment
- 실제 1개의 개별 화면을 구성하는 페이지이다.
FragmentPagerAdapter
- 적고 고정된 수의 페이지 간을 탐색할 때 사용합니다.
- 모든 페이지(Fragment)를 메모리에 유지킨다(페이지가 많다면 메모리 소비가 심함)
- 페이지 수가 적어 모두 메모리에 생성되어 있다면 사용자가 이전 페이지와 앞 페이지를 지속적으로 탐색을 해야되는 경우, 유용하다.
FragmentStatePagerAdapter
- 페이지의 수가 많거나 그 수가 불분명 하지만 많을것으로 예상되는 (예 전자책) 페이징할 때 사용합니다.
- 사용자가 다른 곳을 탐색할 때 프래그먼트를 삭제하여 메모리 사용량을 최적화합니다
- 이전 페이지, 현재 페이지 ,다음 페이지 3개의 페이지를 생성하여 메모리유지한다.
childFragmentManger( fragment - childFragment 관리)
developer.android.com/guide/fragments/fragmentmanager?hl=ko
구현
1. 페이저가 구현 될 Fragment
class NoteListFragment: Fragment() {
private val TAG = "MainActivity"
private lateinit var binding: FragmentNoteListBinding
private val activityViewModel: NotesViewModel by viewModels()
private lateinit var normalListFragment: NormalNoteListFragment
private lateinit var workNoteListFragment: WorkNoteListFragment
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate<FragmentNoteListBinding>(inflater, R.layout.fragment_note_list, container,false)
binding.noteViewModel = activityViewModel
normalListFragment = NormalNoteListFragment()
workNoteListFragment = WorkNoteListFragment()
Log.d(TAG, "NoteListFragment onCreateView: call")
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// fragment view 생성이 된후 viewPager setting
val pagerAdapter = NoteListPagerAdapter(childFragmentManager)
pagerAdapter.addItem(normalListFragment)
pagerAdapter.addItem(workNoteListFragment)
binding.mViewPager.adapter = pagerAdapter
//TapLayout 설정.
binding.mTabLayout.setupWithViewPager(mViewPager)
Log.d(TAG, "NoteListFragment onViewCreated: call")
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="noteViewModel"
type="com.example.notesapp.NotesViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NoteListFragment">
<com.google.android.material.tabs.TabLayout
android:id="@+id/mTabLayout"
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" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/mViewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mTabLayout" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="32dp"
android:src="@drawable/ic_baseline_add_24"
android:onClick="@{noteViewModel :: navigationToAddNotesFragment}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
2. Adapter
class NoteListPagerAdapter(val fm: FragmentManager): FragmentPagerAdapter(fm) {
var items = ArrayList<Fragment>()
// 페이지 개수
override fun getCount(): Int = 2
// 데이터 설정 및 페이지 반환
override fun getItem(position: Int): Fragment = items[position]
// 페이지 이름
override fun getPageTitle(position: Int): CharSequence {
return "Page${(position + 1)}"
}
// 페이지 1개 추가
fun addItem(item: Fragment) {
items.add(item)
}
// 페이지 list로 추가
fun addItems(items: ArrayList<Fragment>){
this.items = items
}
}
3. 각각 페이지가 될 Fragment
class NormalNoteListFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_private_note_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
}
class WorkNoteListFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_normal_note_list, container, false)
}
}
**LifeCycle
mainActivity 위에 NoteFragment 설정 후 NoteFragment안에 페이저를 구현하였다.
일반적인 NoteFragment가 활성상태(onResume) 이후 페이지(Fragment) 생명주기가 순차적으로 실행된다
페이저가 있는 프래그먼트에서 다른 프래그먼트로 이동시.
**각각의 페이지에 viewModel을 연결해보자
mainActivity
private val mViewModel: NotesViewModel by viewModels()
하위 및 손자 프래그먼트
private val activityViewModel: NotesViewModel by activityViewModels()
class MainActivity : AppCompatActivity() {
private val TAG = "lifecycle"
private val VTAG = "viewModel"
private lateinit var mBinding: ActivityMainBinding
private lateinit var navController: NavController
private lateinit var appBarConfiguration: AppBarConfiguration
private val mViewModel: NotesViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mBinding.viewModel = mViewModel
Log.d(TAG, "MainActivity onCreate: call")
Log.d(VTAG, "MainActivity ${mViewModel.getRef()}")
}
}
class NoteListFragment: Fragment() {
private val TAG = "lifecycle"
private val VTAG = "viewModel"
private lateinit var binding: FragmentNoteListBinding
private val activityViewModel: NotesViewModel by activityViewModels()
private lateinit var normalListFragment: NormalNoteListFragment
private lateinit var workNoteListFragment: WorkNoteListFragment
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_note_list, container,false)
binding.noteViewModel = activityViewModel
normalListFragment = NormalNoteListFragment()
workNoteListFragment = WorkNoteListFragment()
Log.d(TAG, "NoteListFragment onCreateView: call")
Log.d(VTAG, "NoteListFragment ${ activityViewModel.getRef()}")
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// fragment view 생성이 된후 viewPager setting
val pagerAdapter = NoteListPagerAdapter(childFragmentManager)
pagerAdapter.addItem(normalListFragment)
pagerAdapter.addItem(workNoteListFragment)
binding.mViewPager.adapter = pagerAdapter
//TapLayout 설정.
binding.mTabLayout.setupWithViewPager(mViewPager)
Log.d(TAG, "NoteListFragment onViewCreated: call")
}
}
class NormalNoteListFragment : Fragment() {
private val TAG = "lifecycle"
private val VTAG = "viewModel"
private lateinit var binding: FragmentNormalNoteListBinding
private val activityViewModel: NotesViewModel by activityViewModels()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_normal_note_list, container, false)
binding.noteViewModel = activityViewModel
Log.d(TAG, "NormalNoteListFragment onCreateView: call")
Log.d(VTAG, "NormalNoteListFragment ${activityViewModel.getRef()}")
return binding.root
}
}
class WorkNoteListFragment : Fragment() {
private val TAG = "lifecycle"
private val VTAG = "viewModel"
private lateinit var binding: FragmentWorkNoteListBinding
private val activityViewModel: NotesViewModel by activityViewModels()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_work_note_list, container, false)
binding.noteViewModel = activityViewModel
Log.d(TAG, "WorkNoteListFragment onCreateView: call")
Log.d(VTAG, "WorkNoteListFragment ${activityViewModel.getRef()}")
return binding.root
}
}
동일한 참조를 얻음.