Group Study (2023-2024)/Android 입문

[Android 입문] 4주차 스터디 -Viewpager2, TabLayout, Navigation View

Sominee 2023. 11. 29. 05:57

1. Viewpager2

  • ViewPager 라이브러리의 개선된 버전으로, 세로 페이징 (android:orientation="vertical")과 오른쪽에서 왼쪽 페이징 (android:layoutDirection="rtl")을 지원한다.
  • 화면 슬라이드: 하나의 전체 화면에서 다른 전체 화면으로 전환하는 것
  • Viewpager2 객체를 활용하여 스와이프로 화면 전환을 구현할 수 있다. 

Viewpager2를 쓰기 위해서 build.gradle.kts (Module :app)에서 플러그인을 추가해줘야 한다.

dependencies {

    implementation("androidx.viewpager2:viewpager2:1.0.0")
    
}

Viewpager2를 사용하기 위해 화면에 보여줄 프래그먼트 레이아웃과 클래스를 작성해주고, Viewpager2의 adpater를 만들어준다.

class MyPagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
    // 외부에서 FragmentActivity를 받아와서 그걸 처리.
    private val NUM_PAGES = 3

    override fun getItemCount(): Int = NUM_PAGES
    // 만들어줄 전체 페이지 수

    override fun createFragment(position: Int): Fragment {
        // 각 페이지가 어떤 프래그먼트로 만들어질지 내용 전해줌.
        return when (position) {
            0 -> { MyFragment.newInstance("Page 1", "")}
            1 -> { MyFragment.newInstance("Page 2", "")}
            else -> { MyFragment.newInstance("Page 3", "")}
        }
    }
}

activity_main.xml에서 메인 액티비티 화면을 구성하는데 여기서 뷰페이저를 배치해준다. 다음으로 구현할 TabLayout을 위해 viewpager 아래에 appBarLayout을 배치하고 그 안에 TabLayout을 배치해주었다.

<?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.viewpager2.widget.ViewPager2
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:id="@+id/viewpager"
        android:orientation="horizontal"
        app:layout_constraintBottom_toTopOf="@+id/appBarLayout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/appBarLayout"
        android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <com.google.android.material.tabs.TabLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:id="@+id/tabs"
            android:background="@color/white"
            app:tabIndicatorColor="@color/design_default_color_primary"
            app:tabRippleColor="@color/design_default_color_primary"
            app:tabSelectedTextColor="@color/design_default_color_primary"
            app:tabTextColor="@color/black"/>

    </com.google.android.material.appbar.AppBarLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity 클래스에서 뷰페이저 어뎁터를 연결시켜준다. setPageTransformer 함수를 이용하여 화면 슬라이드 애니메이션 설정을 할 수 있다. 구글에서 ZoomOutPageTransformer, DepthPageTransformer 와 같이 전환 효과를 구현할 수 있는 코드를 공개하고 있다. 이를 복사해서 클래스를 만들고 활용하면 보다 더 풍부한 화면 전환 효과를 나타낼 수 있다.

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // 어뎁터 설정
        binding.viewpager.apply {
            adapter = MyPagerAdapter(context as FragmentActivity)
            // MyPagerAdapter 객체 만들어서 뷰페이저 어뎁터 속성에 연결

            setPageTransformer(ZoomOutPageTransformer())
            // 페이지 슬라이드 효과
        }

    }
}

 

Viewpager2 실습 영상

2. TabLayout

  • TabLayout을 사용하면 탭을 가로로 나타낼 수 있다.
  • Viewpager와 TabLayout을 함께 사용하면 스와이프 뿐만 아니라 탭 버튼을 통해서도 화면 전환이 가능하다.
  • 탭으로 어떤 페이지에 있는지 직관적으로 알 수 있도록 하여 탐색의 용이성을 제공한다.

메인 액티비티 레이아웃에 TabLayout을 배치한다. 이에 대한 코드는 위의 1번 내용에 있다.

TabLayout을 사용하기 위해 MainActivity 클래스에 TabLayoutMediator를 사용한다. 메뉴 바를 나타내기 위해 res>drawable 에 아이콘을 추가하고 배열에 넣어준다. 

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    // 메뉴 바 아이콘 배열
    private val tabIcon = listOf(
        R.drawable.ic_baseline_format_list_bulleted_24,
        R.drawable.ic_baseline_map_24,
        R.drawable.ic_baseline_info_24
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.viewpager.apply {
            adapter = MyPagerAdapter(context as FragmentActivity)

            setPageTransformer(ZoomOutPageTransformer())
        }

        // 탭 레이아웃과 뷰페이저2를 연결할 때 TabLayoutMediator 씀.
            TabLayoutMediator(binding.tabs, binding.viewpager) { tab, position ->
                tab.text = "Title $position"
                tab.setIcon(tabIcon[position]) // 포지션에 따라 서로 다른 아이콘을 가져오도록, 탭에 아이콘을 지정하기 위해 setIcon 함수 이용.
            }.attach()
    }
}

 

TabLayout 실습 영상

3. Navigation View

바텀 네비게이션을 구현하기 위해 build.gradle.kts (Module :app)에서 플러그인을 추가해준다.

dependencies {
    // 메테리얼 디자인
    implementation("com.google.android.material:material:1.10.0")
}

메인 액티비티 레이아웃에 바텀 네비게이션을 배치해준다. 그리고 activity_main.xml과 같은 위치인 res>layout에 프래그먼트 레이아웃을 원하는 개수만큼 만든다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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"
    android:background="#D8D8D8">

    <FrameLayout
        android:id="@+id/fragments_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/bottom_nav"
        android:layout_centerHorizontal="true"
        android:background="@color/design_default_color_primary"/>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
        app:menu="@menu/bottom_nav_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="#fff"
        app:labelVisibilityMode="unlabeled"
        app:itemIconSize="40dp" />

</RelativeLayout>

다음은 프래그먼트 클래스 중 하나의 코드이다. 외부에서 접근할 때 메모리에 올린 것을 가져오기 위해 compation object 안에 fragment 인스턴스를 만들어 반환하는 코드를 넣어준다.

class HomeFragment : Fragment() {
    companion object {
        // Fragment 인스턴스를 만들어 반환
        fun newInstance() : HomeFragment {
            return HomeFragment()
        }
    }
    
    // 메모리에 올라갔을 때
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
    // 프래그먼트를 안고 있는 액티비티에 붙었을 때
    override fun onAttach(context: Context) {
        super.onAttach(context)
    }

    // 뷰가 생성되었을 때
    // 프래그먼트와 레이아웃을 연결시켜주는 부분이다.
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_home, container, false)

        return view
    }
}

다음은 메인 액티비티 클래스 코드이다. 바텀 네비게이션에서 버튼이 클릭되었을 때 메인 액티비티에서 반응을 할 수 있도록 BottomNavigation.OnNavigationItemSelectedListener를 추가한다. 버튼이 클릭되었을 때 그에 해당하는 프래그먼트를 보여주기 위해 리스너 안에 supportFragmentManager를 사용하여 교체 설정을 넣는다. 초기 화면에는 홈 화면이 나타나도록 add를 사용한다.

class MainActivity : AppCompatActivity(){
    private var mBinding: ActivityMainBinding? = null
    private val binding get() = mBinding!!

    private lateinit var homeFragment: HomeFragment
    private lateinit var rankingFragment: RankingFragment
    private lateinit var profileFragment: ProfileFragment

    // 메모리에 올라갔을 때
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.bottomNav.setOnNavigationItemSelectedListener(onBottomNavItemSelectedListener)
        
        // 초기 화면으로 HomeFragment를 추가하여 표시
        homeFragment = HomeFragment.newInstance()
        supportFragmentManager.beginTransaction().add(R.id.fragments_frame, homeFragment).commit()
    }

    // 바텀네비게이션 아이템 클릭 리스너 설정
    private val onBottomNavItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener {
        when(it.itemId) {
            R.id.menu_home -> {
                homeFragment = HomeFragment.newInstance() // 프래그먼트를 가져옴.
                supportFragmentManager.beginTransaction().replace(R.id.fragments_frame, homeFragment).commit()
                // supportFragmentManager : 프래그먼트 관리
            }
            R.id.menu_ranking -> {
                rankingFragment = RankingFragment.newInstance()
                supportFragmentManager.beginTransaction().replace(R.id.fragments_frame, rankingFragment).commit()
            }
            R.id.menu_profile -> {
                profileFragment = ProfileFragment.newInstance()
                supportFragmentManager.beginTransaction().replace(R.id.fragments_frame, profileFragment).commit()
            }
        }
        true
    }

}

 

Navigation View 실습 영상

 

<참고>

https://developer.android.com/training/animation/screen-slide-2?hl=ko

 

ViewPager2로 프래그먼트 간 슬라이드  |  Android 개발자  |  Android Developers

ViewPager2로 프래그먼트 간 슬라이드 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 화면 슬라이드는 하나의 전체 화면에서 다른 전체 화면으로 전환하는 것

developer.android.com

https://developer.android.com/guide/navigation/navigation-swipe-view-2?hl=ko

 

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

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

developer.android.com

https://cliearl.github.io/posts/android/viewpager2-tablayout/

 

ViewPager2와 TabLayout을 이용해 스와이프 되는 화면 구현하기

이번 포스팅에서는 ViewPager2와 TabLayout을 이용해 스와이프 되는 화면을 구현해 보도록 하겠습니다. ViewPager2를 사용하는 이유나 장점에 대해서는 ViewPager1 프로젝트를 ViewPager2 프로젝트로 변환하기

cliearl.github.io