관리 메뉴

나만을 위한 블로그

[Android] 코틀린으로 TabLayout, ViewPager, Fragment를 활용해서 화면 넘기기 구현하기 본문

Android

[Android] 코틀린으로 TabLayout, ViewPager, Fragment를 활용해서 화면 넘기기 구현하기

참깨빵위에참깨빵 2021. 2. 10. 19:18
728x90
반응형

예전에 자바로 된 같은 내용의 포스팅을 작성한 적이 있다.

onlyfor-me-blog.tistory.com/197

 

[Android] TabLayout, ViewPager, Fragment를 활용해서 화면 넘기기 구현하기

이번 글에선 탭 레이아웃과 뷰페이저, 프래그먼트를 써서 좌우로 화면 넘기기 예제를 구현할 것이다. 먼저 앱 수준 gradle에다가 의존성을 하나 추가해준다. implementation 'com.google.android.material:materi

onlyfor-me-blog.tistory.com

이번엔 코틀린으로 위 내용을 어떻게 구현하는지에 대해 포스팅하려고 한다.

역시 아래 의존성은 꼭 넣어야 한다. 뷰페이저, 탭 레이아웃, 리사이클러뷰 등의 머티리얼 디자인 요소들을 한방에 바로 사용할 수 있게 해준다.

 

implementation 'com.google.android.material:material:1.3.0-alpha01'

 

 

액티비티의 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=".AfterLoginActivity">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/after_login_viewpager"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintWidth_percent="1"
        app:layout_constraintHeight_percent=".9"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/after_login_tablayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintWidth_percent="1"
        app:layout_constraintHeight_percent=".1"
        app:tabIndicatorColor="@color/colorPrimaryDark"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/after_login_viewpager">

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="메인"/>

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="검색"/>

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="내 서재"/>

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="마이페이지"/>

    </com.google.android.material.tabs.TabLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

탭 레이아웃 안에 탭 아이템이 있는 걸 볼 수 있다. 그리고 나는 탭이 바닥에 있는 걸 선호해서 뷰페이저를 위에 두고 그 밑에 탭 레이아웃을 뒀는데, 반대로 탭이 맨 위로 올라가도록 하고 싶다면 뷰페이저와 탭 레이아웃의 위치를 서로 바꾸면 된다. ConstraintLayout을 썼기 때문에 체인만 신경써서 바꿔주면 별 문제없이 작동한다.

 

이제 각각의 탭 아이템을 누르면 나올 프래그먼트를 만들어준다.

프래그먼트 이름은 각각 MainFragment, SearchFragment, LibraryFragment, MyPageFragment로 지었고, 각 프래그먼트의 xml 및 자바 코드는 아래로 통일했다.

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainFragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:text="메인 프래그먼트"
        android:textSize="20sp"/>

</androidx.constraintlayout.widget.ConstraintLayout>
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

class MainFragment : Fragment()
{
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View?
    {
        return inflater.inflate(R.layout.fragment_main, container, false)
    }
}

 

xml 안의 텍스트뷰는 프래그먼트가 제대로 나오는지 확인하기 위해 넣은 텍스트뷰다. 테스트가 끝나면 지우고 다른 뷰나 위젯으로 채워넣으면 된다.

 

이제 이 포스팅에서 가장 중요한 요소인 어댑터를 만들어보자. 프래그먼트 다 만들어놓고 어댑터 안 만들면 말짱 도루묵이다.

 

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter

class PagerAdapter(manager: FragmentManager): FragmentPagerAdapter(manager)
{
    private val fragmentList = ArrayList<Fragment>()
    private val titleList = ArrayList<String>()

    override fun getItem(position: Int): Fragment = fragmentList[position]

    override fun getCount(): Int = titleList.size

    override fun getPageTitle(position: Int): CharSequence = titleList[position]

    fun addFragment(fragment: Fragment, title: String)
    {
        fragmentList.add(fragment)
        titleList.add(title)
    }

}

 

코틀린은 메서드 몸통 안의 코드가 한 줄로 끝나는 경우 =을 써서 간단하게 메서드를 만들 수 있기 때문에 자바에 비해 상대적으로 코드가 많이 짧다.

위 코드 기준 9, 10번 줄의 ArrayList는 각각 프래그먼트와 제목을 담기 위한 ArrayList고, 맨 밑의 addFragment()의 인자로 프래그먼트와 문자열이 넘어오면 그것들을 각각 ArrayList에 집어넣어서 탭 레이아웃에서 보여지도록 할 때 필요하다.

getItem(), getCount()는 FragmentPagerAdapter를 구현할 경우 단축키를 통해 자동으로 만들 수 있지만, getPageTitle()만은 메서드명을 직접 타이핑해서 재정의해야 한다.

마지막으로 이것을 적용한 액티비티의 코드다.

 

import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.kotlinproj.Library.LibraryFragment
import com.example.kotlinproj.MyPage.MyPageFragment
import com.example.kotlinproj.Search.SearchFragment
import kotlinx.android.synthetic.main.activity_after_login.*

class AfterLoginActivity : AppCompatActivity()
{
    private lateinit var context: Context

    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_after_login)

        val adapter = PagerAdapter(supportFragmentManager)
        adapter.addFragment(MainFragment(), "메인")
        adapter.addFragment(SearchFragment(), "검색")
        adapter.addFragment(LibraryFragment(), "내 서재")
        adapter.addFragment(MyPageFragment(), "마이페이지")
        after_login_viewpager.adapter = adapter
        after_login_tablayout.setupWithViewPager(after_login_viewpager)
    }

}

 

val adapter에 위에서 만든 어댑터를 매핑한 다음 addFragment()를 호출해서 사용할 프래그먼트와 탭 아이템에 붙일 이름을 넣는 걸 볼 수 있다.

그리고 뷰페이저에 어댑터를 붙인 다음, 이 뷰페이저를 탭 레이아웃에 붙이면 끝이다.

여기까지 한 후 빌드해서 확인해보면 아래와 같이 작동한다.

 

마이페이지 프래그먼트 글자에는 다른 폰트를 적용했기 때문에 이 글자만 다른 폰트로 나온다. 신경쓰지 않아도 된다

 

마지막으로 xml에서 탭 레이아웃에 적용할 수 있는 옵션들을 정리한 다음 포스팅을 마무리한다.

코드를 보면 알겠지만 아래 옵션들은 코드에서 어느 것도 적용하지 않았다. 자신의 입맛에 맞춰 사용하자.

 

app:tabGravity = 탭의 정렬 방식을 지정하는 옵션이다.

  • fill : 각 탭의 넓이를 동일한 간격으로 맞춘다
  • center : 탭을 가운데로 정렬한다

app:tabMode = 탭의 표시 방식을 지정한다.

  • fixed : 모든 탭이 나오도록 설정한다
  • scrollable : 탭이 화면 밖을 나갈 경우 스크롤되도록 설정한다. 위 예제에서 이 옵션을 적용할 경우 모든 탭이 왼쪽으로 쏠리는데 언제 쓰는진 모르겠다.

app:tabIconTint = 아이콘 색을 결정한다. 이 예제처럼 커스텀 뷰를 쓰는 경우엔 쓸모없는 옵션이다.

app:tabSelectedTextColor = 탭이 선택됐을 때 글자 색을 바꾸는 옵션이다.

app:tabIndicatorColor = 탭이 선택될 때마다 글자 밑의 얇은 가로선이 나오는 걸 볼 수 있다. 이걸 탭 인디케이터라고 하는데 이것의 색을 바꾸는 옵션이다.

app:tabIndicatorHeight = 탭 인디케이터의 높이를 설정하는 옵션이다.

 

 

참고)

 

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

 

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

스와이프 뷰를 사용하면 손가락의 가로 동작이나 스와이프로 탭과 같은 동위 화면 간을 탐색할 수 있습니다. 이러한 탐색 패턴을 가로 페이징이라고도 합니다. 이 주제에서는 탭 간 전환을 위해

developer.android.com

 

kangmin1012.tistory.com/12

 

[Kotiln/Android] TabLayout과 ViewPager를 이용한 화면 이동

안드로이드 개발함에 있어서 하단 탭은 자주 등장한다. 보통 하단 탭을 이용할 때 BottomNavigation을 이용하였는데, 좀 더 유연하게 TabLayout과 ViewPager를 통해 여러 Fragment를 이동하는 실습을 해보겠

kangmin1012.tistory.com

 

반응형
Comments