안드로이드

[안드로이드] Fragment 이해하기(3) / ViewPager 뷰페이저

edit0 2021. 1. 4. 00:27

ViewPager는 손으로 좌, 우 스크롤하여 화면을 넘길 수 있는 기능을 제공한다.

1. 프래그먼트를 넣어 스크롤을 이용해 프래그먼트를 전환할 수 있도록 만들어 보겠다.

2. 그리고 이전 포스팅에서 했던 TabLayout과 결합하여 스크롤을 하거나 탭을 누르면 화면이 넘어가도록 호환되게 만들어 보도록 하겠다.

 

 

ViewPager를 사용하기 전에 외부 라이브러리를 추가해주어야 한다.

dependency 추가할 때

API 28 이하는

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

API 29 부터는

implementation 'com.google.android.material:material:1.0.0'

 

액티비티는 화면 3개와 ViewPager를 담을 메인 xml, 액티비티로 구성된다.

 

3개 화면은 아래 코드로 구현할 수 있다.

이 방식으로 2개 더 만들면 된다.(복붙으로 숫자만 바꿔주면 된다)

fragment_fragment1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context=".fragment1"
    android:orientation="vertical"
    android:gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30dp"
        android:text="첫번째"/>

</LinearLayout>

 

fragment2.java

public class fragment1 extends Fragment {

    ViewGroup viewGroup;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        viewGroup = (ViewGroup) inflater.inflate(R.layout.fragment_fragment1, container, false);

        return viewGroup;
    }
}

 

주요 코드

 

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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <androidx.viewpager.widget.ViewPager
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/viewpager" />

</LinearLayout>

 

MainActivity.java

public class MainActivity extends AppCompatActivity {

    fragment1 f1;
    fragment2 f2;
    fragment3 f3;
    ViewPager viewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager = findViewById(R.id.viewpager);
        viewPager.setOffscreenPageLimit(3); //화면 갯수 설정

        f1 = new fragment1();
        f2 = new fragment2();
        f3 = new fragment3();

        //getSupportFragmentManager를 아래 내부 클래스 생성자 fm변수에 넣어준다.
        //넣어줌으로써 프래그먼트 관리가 가능하다.
        viewpagerAdapter adapter = new viewpagerAdapter(getSupportFragmentManager());
        //만들어진 어댑터로 화면을 추가해준다.
        adapter.addItemfragment(f1);
        adapter.addItemfragment(f2);
        adapter.addItemfragment(f3);

	//ViewPager에 어댑터 장착
        viewPager.setAdapter(adapter);
        
    }

    //Adapter는 ViewPager에 보여줄 각 프래그먼트를 관리하는 역할
    class viewpagerAdapter extends FragmentStatePagerAdapter{
        ArrayList<Fragment> items = new ArrayList<>(); //프래그먼트 화면을 담아둘 배열
        //내부 클래스로 FragmentStatePagerAdapter 상속

        //프래그먼트(화면) 관리를 위해 FragmentManager를 파라미터로 받는다.
        public viewpagerAdapter(FragmentManager fm){
            super(fm);
        }

        //ArrayList에 add로 화면 추가하는 메소드
        public void addItemfragment(Fragment item){
            items.add(item);
        }

        @NonNull
        @Override
        //프래그먼트를 가져갈 수 있는 메소드
        public Fragment getItem(int position) {
            return items.get(position);
        }

        @Override
        //현재 프래그먼트(화면) 갯수 확인
        public int getCount() {
            return items.size();
        }
    }
}

* Adapter는 사용자가 정의한 데이터 리스트를 입력으로 받아들여 화면에 표시할 뷰(View)들을 생성

 

결과

 

 

이제부터 TabLayout을 포함하여 구현해보도록 하겠다.

 

이전 포스팅해서 하였던 것처럼 TabLayout을 만들어준다. 문제는 TabLayout과 ViewPager의 화면이 전환될 때 동기화를 해주어야 한다는 점인데 이것만 이해한다면 다른 것은 똑같아서 이해하기 쉬울 것이다.

 

동기화를 하는데 필요한 메소드는 ViewPager의 .addOnPageChangeListener() 이다.

.addOnPageChangerListener()는 페이지를 넘기는 과정에서 호출되는 부분으로 뷰페이저가 스크롤하면 이 때 탭에게 "나 화면 전환하니 너도 바꿔줘" 라고 호출을 보낼 수 있다. 이 과정으로 뷰페이저를 스크롤하면 탭의 아이템 항목도 함께 움직인다.

탭은 이전 포스팅에서 했던 것처럼 .addOnTabSelectedListener() 리스너 내에 .onTabSelected() 메소드를 호출하여 탭 아이템 항목 클릭 시 뷰페이저도 함께 움직이도록 설정해줄 수 있다.

 

코드

 

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"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <com.google.android.material.tabs.TabLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tab"
        app:tabMode="fixed"
        app:tabGravity="fill"/>

    <androidx.viewpager.widget.ViewPager
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/viewpager" />

</LinearLayout>

 

MainActivity.java

public class MainActivity extends AppCompatActivity {

    fragment1 f1;
    fragment2 f2;
    fragment3 f3;
    ViewPager viewPager;
    TabLayout tabLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager = findViewById(R.id.viewpager);
        tabLayout = findViewById(R.id.tab);

        f1 = new fragment1();
        f2 = new fragment2();
        f3 = new fragment3();

        viewPager.setOffscreenPageLimit(3); //화면 갯수 설정

        //getSupportFragmentManager를 아래 내부 클래스 생성자 fm변수에 넣어준다.
        //넣어줌으로써 프래그먼트 관리가 가능하다.
        viewpagerAdapter adapter = new viewpagerAdapter(getSupportFragmentManager());

        //만들어진 어댑터로 화면을 추가해준다.
        adapter.addItemfragment(f1);
        adapter.addItemfragment(f2);
        adapter.addItemfragment(f3);

        //뷰페이저에 어댑터(화면들) 장착
        viewPager.setAdapter(adapter);

        //addTab() 메소드를 사용하여 탭 버튼 추가
        tabLayout.addTab(tabLayout.newTab().setText("1"));
        tabLayout.addTab(tabLayout.newTab().setText("2"));
        tabLayout.addTab(tabLayout.newTab().setText("3"));

        //뷰페이저의 페이지가 넘어갈 때마다 화면 변경 이벤트를 탭에 전달하여 동기회해주는 역할
        //바로 아래 부분 코드를 객체로 만들어서 바로 넣어주었다고 생각하면 된다.
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

        //탭 버튼 이벤트 처리를 위한 리스너 생성 후 3개 메소드 오버라이드
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                //선택되지 않았던 탭이 선택되었을 경우
                viewPager.setCurrentItem(tab.getPosition());
                //Tab이 눌리면 그에 맞는 번호를 ViewPager에도 설정해줌으로써 화면 번호가 맞도록 조정

            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                //탭이 선택된 상태에서 선택되지 않음으로 변경될 경우
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                //이미 선택된 탭이 다시 선택되었을 경우
            }
        });
    }

    //Adapter는 ViewPager에 보여줄 각 프래그먼트를 관리하는 역할
    class viewpagerAdapter extends FragmentStatePagerAdapter{
        ArrayList<Fragment> items = new ArrayList<>(); //프래그먼트 화면을 담아둘 배열
        //내부 클래스로 FragmentStatePagerAdapter 상속

        //프래그먼트(화면) 관리를 위해 FragmentManager를 파라미터로 받는다.
        public viewpagerAdapter(FragmentManager fm){
            super(fm);
        }

        //ArrayList에 add로 화면 추가하는 메소드
        public void addItemfragment(Fragment item){
            items.add(item);
        }

        @NonNull
        @Override
        //프래그먼트를 가져갈 수 있는 메소드
        public Fragment getItem(int position) {
            return items.get(position);
        }

        @Override
        //현재 프래그먼트(화면) 갯수 확인
        public int getCount() {
            return items.size();
        }
    }
}

 

결과

 

 

 

부족한 점, 피드백 환영합니다.

 

감사합니다.

 

 

참고

정재곤, 『Do it! 안드로이드 앱 프로그래밍 - 개정 6판』, 이지스퍼블리싱(주)