Apple is Apple

TabLayout & ViewPager2

TabLayout

TabLayout은 탭(tab)으로 구분하는 화면에서 탭 버튼을 배치하는 레이아웃이다.

 

보통 앱바 바로 하단에 붙어 탭 구분을 해서 여러 화면을 보여 줄 수 하게 뜸하다.

 

탭은 보통 상단에 위치하기에 불편한 점이 종종 있다. 바로 기기의 화면이 크면 (스마트폰 기준) 한 손으로는 탭을 터치하기가 불편하다는 점이다.

 

이를 해소할 수 있는 방법이 있는데 TabLayout에 ViewPager를 적용시켜 주는 것이다.

 

ViewPager는 좌우 스크롤을 통해 화면을 넘길 수 있는 기능을 제공한다.

 

좌우 스크롤을 통해 손가락을 위로 올리는 불편함 없이 편한 자세로 스크롤하여 탭을 제어할 수 있다.

 

ViewPager2

ViewPager는 좌우 스크롤을 통해 화면을 넘길 수 있는 기능을 제공한다.

 

액티비티에서 화면을 전환하여 보여주기 때문에 fragment 사용하여 구현하고, 여러 fragment 중 하나를 선택하는 형태의 view이기 때문에 recyclerview와 같이 어댑터를 사용하여 데이터를 분배해주어야 한다.

 

ViewPager2는 ViewPager의 개선된 버전으로 향상된 기능을 제공하고, ViewPager 사용 시
발생하는 문제들을 해결한다. 그래서 요즘에는 ViewPager2를 주로 사용한다.

 

ViewPager2를 사용하여 탭으로 스와이프 뷰 만들기

TabLayout과 ViewPager2를 사용하여 과제에 적용시켜 보자

 

1. ViewPager2는 외부라이브러리에 존재하므로 의존성을 추가시켜 주었다.

implementation "androidx.viewpager2:viewpager2:1.0.0"

버전은 1.1.0까지 있었는데 1.1.0은 베타 버전이어서 안정화된 1.0.0 버전을 적용시켰다.

 

2. 레이아웃 그리기

[ activity_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=".MainActivity">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize"
        app:title="@string/app_name"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"

        android:layout_height="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar">
    </com.google.android.material.tabs.TabLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tabLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

과제의 화면을 보면 위쪽으로 탭이 보이고 아래쪽에 보이는 데이터 영역이 있어 TabLayout을 위쪽에 배치 ViewPager2를 아래쪽에 배치하였다. (Constraint layout의 constraint적용)

 

3. TabLayout과 ViewPager2 연결

레이아웃을 그린 후 액티비티에서 코드로 TabLayout과 ViewPager2를 연결시켰다.

 

[ MainActivity.kt ]

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val titleList by lazy {
        listOf(
            getString(R.string.to_do),
            getString(R.string.to_do_bookmarked)
        )
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initViews()
    }

    private fun initViews() = with(binding) {
        pager.adapter = FragmentAdapter(supportFragmentManager, lifecycle)
        TabLayoutMediator(tabLayout, pager) { tab, pos ->
            tab.text = titleList[pos]
        }.attach()
    }
}

위의 ViewPager 설명에서 '여러 fragment 중 하나를 선택하는 형태의 view이기 때문에 recyclerview와 같이 어댑터를 사용하여 데이터를 분배해주어야 한다'라고 했으므로 viewpager의 어댑터를 연결시켜주어야 한다. 이건 밑에서 살펴보겠다.

 

TabLayoutMediator가 중요한 부분인데, 이 부분이 TabLayout과 ViewPager를 연결시켜 준다.

 

TabLayoutMediator 공식문서를 살펴보면 'TabLayout을 ViewPager2와 연결하는 중재자입니다. 중재자는 탭이 선택될 때 ViewPager2의 위치를 ​​선택한 탭과 동기화하고 사용자가 ViewPager2를 드래그할 때 TabLayout의 스크롤 위치를 동기화합니다. TabLayoutMediator를 인스턴스화하면 중재자 개체가 생성되고 attach()를 호출하면 TabLayout과 ViewPager2가 함께 연결됩니다.'라고 설명하고 있다.

 

TabLayout과 ViewPager를 선언하여도 Mediator로 연결시켜주지 않으면 Swipe 동작은 하지 않기 때문에 반드시 연결 작업을 진행해주어야 한다.

 

TabLayoutMediator() 뒤에 붙은 람다식은 새로 생성된 탭의 텍스트 및 스타일을 설정하기 위해 구현해야 하는 콜백 인터페이스이다. 이곳에서 탭의 이름 및 스타일을 정의해 줄 수 있다. 위의 코드에서는 탭의 이름을 정의해 주었다.

 

 

[ FragmentStateAdapter.kt ] 

class FragmentAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle)
    : FragmentStateAdapter(fragmentManager, lifecycle) {

    override fun getItemCount(): Int = 2

    override fun createFragment(position: Int): Fragment {
        // 그냥 호출이 아니라 return을 해줘야함 중요
       when(position) {
           0 -> {
               return ToDoFragment()
           }
           1 -> {
               return BookmarkedToDoFragment()
           }
       }
        return ToDoFragment()
    }
}

FragmentStateAdapter -

필수로 구현해야하는 메서드

getItemCount() ViewPager 하위에 들어갈 아이템(페이지)의 수
createFragment() ViewPager 위치에 따라 표현해야할 페이지(Fragment) 지정

이 부분은 아직 공부가 많이 되지 않아 추가 학습이 필요하다. 추후에 글을 써보도록 하겠다.

아주 잘 정리된 글이 있어 소개해본다. 이 글을 보면 FragmentStateAdapter에 대한 느낌을 얻을 수 있을 것이다.

 

 

 

<-- 필요시 내용 업데이트 -->

 

 

ref.

 

FragmentStateAdapter  |  Android Developers

 

developer.android.com

 

ViewPager2를 사용하여 탭으로 스와이프 뷰 만들기  |  Android 개발자  |  Android Developers

ViewPager2를 사용하여 탭으로 스와이프 뷰 만들기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 스와이프 뷰를 사용하면 손가락의 가로 동작이나 스와이프

developer.android.com

https://heechokim.tistory.com/23

'Android' 카테고리의 다른 글

[Android] ActionBar? ToolBar!  (0) 2023.08.11
[Android] RecyclerView  (0) 2023.08.10
[Android] Activity Lifecycle - 2  (0) 2023.08.02
[Android] Activity Lifecycle  (0) 2023.08.02
[Android UI] PX, DPI, DP (feat. 다양한 기기와 해상도)  (0) 2023.08.01
profile

Apple is Apple

@mjjjjjj