ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] TabLayout과 ViewPager
    프로그래밍/Android 2018. 9. 19. 16:19

    포스팅 하려는 목록들을 정리하다 보니, 생각보다 많아 언제 다하지.. 하는 생각만 드네요.. 욕심이 과한 걸까요..ㅠ 

    그래도 포기하지 않고 천천히라도 하나씩 하나씩  포스팅해봐야겠어요.!


    오늘 소개해드릴 것은 TabLayout과 ViewPager에 관한 이야기입니다.

    TabLayout은 카카오톡이나 구글플레이 등에서 흔하게 볼 수 있는데 탭 메뉴를 말한답니다. 그리고 탭을 누를 때마다 아래 화면이 마치 페이지가 넘어가듯이 변하는데요, 이 부분은 ViewPager를 이용해 구현이 가능하답니다.


    이전에 포스팅한 ListView처럼, 많이 사용되고 있는 녀석들이라 알아두시면 좋으실 것 같아 준비해보았습니다.

    그럼 시작하겠습니다.!!




        

    GooglePlayStore - 탭 메뉴



    위와 같이, 구글플레이스토어나 카카오톡 등 여러 앱에서 상단의 탭 메뉴의 선택에 따라 아래 화면이 달라지는 구조를 보신 적이 있으실 텐데요. 여러가지 데이터들을 카테고리 별로 구분지어 표현하기에 적합합니다.

    어떻게 만들 수 있냐구요? 바로 Tablayout과 ViewPager를 이용하여 구현이 가능하답니다. 어려운 내용은 아니니, 예제를 통해 천천히 따라오시면 되겠습니다. 



    Gradle에 라이브러리 추가하기

    TabLayout은 Design Support Library에 속해 있으므로, 사용하기 위해서는 우선 Gradle에 라이브러리를 먼저 추가해 주셔야 합니다.


    build.gradle (Module:app)



    dependencies {

        implementation fileTree(dir: 'libs', include: ['*.jar'])

        implementation 'com.android.support:appcompat-v7:26.1.0'

        testImplementation 'junit:junit:4.12'

        androidTestImplementation 'com.android.support.test:runner:1.0.2'

        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'


        implementation 'com.android.support:design:26.1.0'

    }


    라이브러리를 추가하실 때, 주의하실 점은 모든 Support 라이브러리의 버전은 같아야 한다는 것입니다. 위의 예제에서는 appcompat-v7 라이브러리의 버전과 동일하게 26.1.0 버전을 사용하고 있습니다.



    TabLayout 사용하기

    TabLayout은 Tab 메뉴들을 담는 큰 틀이라고 생각하시면 됩니다. 차 후에, TabLayout에 각각의 Tab을 붙여 사용하시게 될 텐데요.

    우선 레이아웃에 TabLayout을 작성하겠습니다.


    activity_main.xml


    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout 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"

        android:gravity="center_horizontal"

        tools:context="rebuild.com.tablayout.MainActivity">


        <android.support.design.widget.TabLayout

            android:id="@+id/layout_tab"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            app:tabGravity="center"

            app:tabMode="fixed"

            app:tabTextColor="#000000"

            app:tabSelectedTextColor="@color/colorPrimary"

            app:tabIndicatorColor="@color/colorPrimary"/>


    </LinearLayout>


    일단은, 상단에 TabLayout만 배치하였습니다. TabLayout에 중요한 옵션이 몇 가지 있는데요, 많이 쓰이는 몇 가지를 살펴보겠습니다.


    • tabGravity

    - tab의 정렬 방식에 대한 옵션입니다.

     

     "center"

     탭을 가운데 정렬하여 표시합니다.

     

     "fill"

     탭의 너비를 동일하게 정렬하여 표시합니다.


    • tabMode

    - tab의 표시 방식에 대한 옵션입니다.

     

     "fixed"

     모든 탭을 화면에 표시되도록 설정합니다.

     

     "scrollable"

     탭이 화면을 넘어갈 시 스크롤이 되도록 설정합니다.


    • tabTextColor

    - tab안의 Text의 색상을 지정합니다.


    • tabSelectedTextColor

    - tab 선택 시에, tab안의 Text의 색상을 지정합니다.


    • tabIndicatorHeight

    - tab 하단의 Indicator의 높이를 지정합니다.


    • tabIndicatorColor

    - tab 하단의 Indicator의 색상을 지정합니다.


    사용해보시면 아시겠지만, tabGravity와 tabMode의 옵션은 layout_width와도 영향이 있으니, 사용에 유의해 주시기 바랍니다. 이어서, MainActivity를 작성하겠습니다.


    MainActivity.java



    package rebuild.com.tablayout.Activity;


    import android.content.Context;

    import android.support.design.widget.TabLayout;

    import android.support.v7.app.AppCompatActivity;

    import android.os.Bundle;


    public class MainActivity extends AppCompatActivity {

        private Context mContext;


        private TabLayout mTabLayout;


        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

            mContext = getApplicationContext();


            mTabLayout = (TabLayout) findViewById(R.id.layout_tab);


            mTabLayout.addTab(mTabLayout.newTab().setText("홈"));

            mTabLayout.addTab(mTabLayout.newTab().setText("게임"));

            mTabLayout.addTab(mTabLayout.newTab().setText("영화"));

            mTabLayout.addTab(mTabLayout.newTab().setText("도서"));

            mTabLayout.addTab(mTabLayout.newTab().setText("뉴스스탠드"));

        }

    }


    위와 같이 작성하고 실행해보시면 문제 없이 잘 나오는 걸 확인하실 수 있으실텐데요, 글자 이외에도 아이콘을 설정하여 넣으실 수 있습니다. 참고로 아이콘은 글자 위로 들어갑니다.!

    그래서 "나는 텍스트 크기도 바꾸고 싶고, 아이콘도 글자 옆에 보이게 하고 싶은데...ㅠ" 하시는 분들이 있으시겠죠?

    방법이 없냐구요? 그렇지 않습니다. 커스텀하여 원하시는 입맛대로 사용이 가능하답니다.


    일단 탭에 넣고자 하는 커스텀뷰를 만들기 위해 레이아웃을 먼저 만들겠습니다.


    custom_tab.xml


    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content">


        <TextView

            android:id="@+id/txt_name"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:textColor="#000000"

            android:textSize="20dp" />


    </LinearLayout>


    예제에서는 TextView 하나만 배치하였지만, 원하시는대로 꾸미시면 되겠습니다.

    다시 MainActivity로 돌아와서, 커스텀뷰를 적용해 보겠습니다.


    MainActivity.java



    package rebuild.com.tablayout.Activity;


    import android.content.Context;

    import android.support.design.widget.TabLayout;

    import android.support.v7.app.AppCompatActivity;

    import android.os.Bundle;

    import android.view.LayoutInflater;

    import android.view.View;

    import android.widget.TextView;


    public class MainActivity extends AppCompatActivity {

        private Context mContext;


        private TabLayout mTabLayout;


        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

            mContext = getApplicationContext();


            mTabLayout = (TabLayout) findViewById(R.id.layout_tab);


            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("홈")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("게임")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("영화")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("도서")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("뉴스스탠드")));

        }


        private View createTabView(String tabName) {

            View tabView = LayoutInflater.from(mContext).inflate(R.layout.custom_tab, null);

            TextView txt_name = (TextView) tabView.findViewById(R.id.txt_name);

            txt_name.setText(tabName);

            return tabView;

        }

    }


    저는 createTabView()라는 메서드를 만들어 TextView에 넣을 제목을 받아 처리 한 뒤, View를 리턴하도록 하였습니다. 리턴받은 View는 setCustomView()를 통해 적용하였습니다.


    생각보다 간단하죠? 필요에 따라 선택하여 작성하시면 되겠습니다.

    이렇게 일단 TabLayout은 잠시 접어두고, 이번엔 ViewPager를 이용하는 법을 알아보겠습니다.



    ViewPager 사용하기

    ViewPager는 앞서 말씀드린 것과 같이 여러 개의 View를 페이지 넘기듯이 사용할 수 있도록 도와주는 위젯입니다.

    우선, ViewPager를 사용하기에 앞서, 각각의 페이지에 해당하는 Fragment들을 먼저 생성하겠습니다.


    Fragment 생성


    위의 그림과 같이 5개의 Fragment를 생성하였습니다. Fragment를 생성하는 방법에 대해서는 따로 설명하지 않겠습니다.

    이번에는 레이아웃에 ViewPager를 추가하겠습니다.


    activity_main.xml


    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout 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"

        android:gravity="center_horizontal"

        tools:context="rebuild.com.tablayout.MainActivity">


        <android.support.design.widget.TabLayout

            android:id="@+id/layout_tab"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            app:tabGravity="center"

            app:tabMode="fixed"

            app:tabTextColor="#000000"

            app:tabSelectedTextColor="@color/colorPrimary"

            app:tabIndicatorColor="@color/colorPrimary"/>


        <android.support.v4.view.ViewPager

            android:id="@+id/pager_content"

            android:layout_width="match_parent"

            android:layout_height="match_parent" />


    </LinearLayout>


    ViewPager도 ListView 등과 마찬가지로 Fragment와 ViewPager를 연결해주는 Adapter가 필요합니다.


    작성법은 어렵지 않으니, 어려움은 없으실 겁니다. 한번 볼까요?


    ContentsPagerAdapter.java



    package rebuild.com.tablayout.Adapter;


    import android.support.v4.app.Fragment;

    import android.support.v4.app.FragmentManager;

    import android.support.v4.app.FragmentStatePagerAdapter;


    import rebuild.com.tablayout.Fragment.BookFragment;

    import rebuild.com.tablayout.Fragment.GameFragment;

    import rebuild.com.tablayout.Fragment.HomeFragment;

    import rebuild.com.tablayout.Fragment.MovieFragment;

    import rebuild.com.tablayout.Fragment.NewsFragment;


    public class ContentsPagerAdapter extends FragmentStatePagerAdapter {

        private int mPageCount;


        public ContentsPagerAdapter(FragmentManager fm, int pageCount) {

            super(fm);

            this.mPageCount = pageCount;

        }


        @Override

        public Fragment getItem(int position) {

            switch (position) {

                case 0:

                    HomeFragment homeFragment = new HomeFragment();

                    return homeFragment;


                case 1:

                    GameFragment gameFragment = new GameFragment();

                    return gameFragment;


                case 2:

                    MovieFragment movieFragment = new MovieFragment();

                    return movieFragment;


                case 3:

                    BookFragment bookFragment = new BookFragment();

                    return bookFragment;


                case 4:

                    NewsFragment newsFragment = new NewsFragment();

                    return newsFragment;


                default:

                    return null;

            }

        }


        @Override

        public int getCount() {

            return mPageCount;

        }

    }


    Adapter는 FragmentStatePagerAdpater를 상속 받아 만들어졌는데요, 생성자를 통해서 Fragment의 관리를 도와주는 FragmentManager와 페이지의 개수를 탭의 개수와 맞춰주기 위해 pageCount를 받아오도록 하였습니다.


    다음은 Override 메서드들에 대한 설명입니다.

    • getItem(int position)

    position에 해당하는 Fragment를 반환합니다.

    예제에서는 탭의 position에 맞추어 Fragment를 생성하여 반환하도록 설정하였습니다.


    • getCount()

    page의 개수를 반환합니다. 반환 되는 수에 따라 페이지의 수가 결정됩니다.

    예제에서는 탭의 개수와 동일하도록 설정하였습니다.


    Adapter에 대한 설정은 이것으로 끝입니다.

    이제 TabLayout과 연결하는 일만 남았군요!. 바로 이어서 진행하도록 하겠습니다.



    TabLayout과 ViewPager 연결하기

    저희가 만들고자 하는 기능은 Tab을 클릭하였을 때, 해당하는 페이지가 보이도록 하는 것이기 때문에 TabLayout의 동작과 ViewPager의 동작을 연결 시켜주는 작업이 필요합니다.


    MainActivity.java



    package rebuild.com.tablayout.Activity;


    import android.content.Context;

    import android.support.design.widget.TabLayout;

    import android.support.v4.view.ViewPager;

    import android.support.v7.app.AppCompatActivity;

    import android.os.Bundle;

    import android.view.LayoutInflater;

    import android.view.View;

    import android.widget.TextView;


    import rebuild.com.tablayout.Adapter.ContentsPagerAdapter;


    public class MainActivity extends AppCompatActivity {

        private Context mContext;


        private TabLayout mTabLayout;


        private ViewPager mViewPager;

        private ContentsPagerAdapter mContentPagerAdapter;


        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

            mContext = getApplicationContext();


            mTabLayout = (TabLayout) findViewById(R.id.layout_tab);


            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("홈")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("게임")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("영화")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("도서")));

            mTabLayout.addTab(mTabLayout.newTab().setCustomView(createTabView("뉴스스탠드")));


            mViewPager = (ViewPager) findViewById(R.id.pager_content);

            mContentsPagerAdapter = new ContentsPagerAdapter(

                                                                getSupportFragmentManager(), mTabLayout.getTabCount());

            mViewPager.setAdapter(mContentsPagerAdapter);


            mViewPager.addOnPageChangeListener(

                                     new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));

            mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

                @Override

                public void onTabSelected(TabLayout.Tab tab) {

                    mViewPager.setCurrentItem(tab.getPosition());

                }


                @Override

                public void onTabUnselected(TabLayout.Tab tab) {


                }


                @Override

                public void onTabReselected(TabLayout.Tab tab) {


                }

            });

        }


        private View createTabView(String tabName) {

            View tabView = LayoutInflater.from(mContext).inflate(R.layout.custom_tab, null);

            TextView txt_name = (TextView) tabView.findViewById(R.id.txt_name);

            txt_name.setText(tabName);

            return tabView;

        }

    }


    ViewPager에 이전에 생성해두었던 Adapter를 setAdapter를 이용해 연결하였습니다.

    여기까지 작성하셨다면, 화면에는 TabLayout과 ViewPager 두 가지 모두 각각 정상적으로 동작은 하겠지만, 서로 연동되어 동작 되지 않습니다. 원하는 동작을 하게 하기 위해서 ViewPager.addOnPageChangeListener와 TabLayout.addOnTabSelectedListener가 필요합니다.


    • addPageChangeListener(OnPageChangeListener listener)

    ViewPager의 페이지가 변경될 때 알려주는 리스너입니다.

    예제에서는 TabLayout.TabLayoutOnPagerChangeListener(TabLayout tabLayout)을 이용하여, ViewPager의 페이지가 변경 될 때 TabLayout에도 알려주도록 설정하였습니다


    • addOnTabSelectedListener(OnTabSelectedListener listener)

    Tab이 선택 되었을 때 알려주는 리스너입니다. 추가하면 다시, Override 메서드가 3가지가 있습니다.

     

    - onTabSelected()

    탭이 선택 되었을 때, 호출됩니다.

     

    - onTabUnselected()

    탭이 선택되지 않았을 때, 호출됩니다. 

     

    - onTabReselected()

    탭이 다시 선택되었을 때, 호출됩니다. 


    위의 예제에서는 탭이 선택되었을 경우, ViewPager의 페이지를 선택된 탭의 포지션에 맞추어 바꾸어 주도록 설정하였습니다.


    실행화면

        

    TabLayout과 ViewPager 실행결과







    TabLayout과 ViewPager 둘 다 각각으로도 많이 사용되니 알아두신다면 분명 도움이 되실 거라 생각합니다.


    어느덧 다시 시간이 흘러 추석이 코앞이네요. 모두 즐거운 추석 보내시길 바라겠습니다.

    수고하셨습니다.!


Designed by Tistory.