[안드로이드] Fragment 이해하기(3) / ViewPager 뷰페이저
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판』, 이지스퍼블리싱(주)