ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Android ViewPager 예제 - 좌우로 스와이프로 화면 전환
    Android/개념 및 예제 2019.10.12 18:57



    좌우로 움직이는 스와이프 제스처로 앱의 화면을 전환을 하는 예제입니다. 


    최초작성 2016. 7. 24

    최종작성 2019. 10. 12



    스와이프(swipe)는 손가락을 화면에 댄 후, 일직선으로 드래그했다가 손을 떼는 동작입니다.

    스와이프하여 이동할 때마다 상단에 있는 인디케이터가 움직여서 현재 위치를 알려줍니다.





    ViewPager는 좌우 스와이프 동작으로 페이지 전환을 가능하도록 해주는 레이아웃 매니저입니다.


    보여지는 뷰를 생성하기 위해서 FragmentPagerAdapter와 FragmentStatePagerAdapter를 사용하여 fragment를 생성할 수 있습니다.

    FragmentStatePagerAdapter는 화면에 보여지지 않는 fragment를 메모리에서 제거하지만 FragmentPagerAdapter는 모든 fragment를 메모리에 유지합니다. 

    메모리에 부담을 주지 않기 위해서 FragmentPagerAdapter에서 생성한 fragment수를 3이하로 하거나 FragmentStatePagerAdapter를 사용하는 것을 권장하고 있습니다.




    다음 과정으로 예제를 테스트할 수 있습니다.


    1. build.gradle에 me.relex:circleindicator를 추가합니다. 인디케이터를 표시하기 위해 필요합니다.


    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.appcompat:appcompat:1.1.0'
        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test:runner:1.2.0'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
        implementation 'me.relex:circleindicator:1.2.2'
    }





    2. drawable 폴더에 black_radius.xml 파일을 추가합니다. 인디케이터를 검은색 동그라미로 표시하기 위해 필요합니다. 


    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
        <solid
            android:color="@android:color/black"/>
    </shape>




    3. activity_main.xml 레이아웃 파일을 추가합니다. 인디케이터와 뷰페이저가 포함되어 있습니다. 


    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical">

        <me.relex.circleindicator.CircleIndicator
            android:id="@+id/indicator"
            app:ci_drawable="@drawable/black_radius"
            app:ci_height="7dp"
            app:ci_width="7dp"
            app:ci_margin="4dp"
            android:layout_width="match_parent"
            android:layout_height="48dp"/>

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


    </LinearLayout>





    4. 프레그먼트를 위한 레이아웃을 추가합니다. 예제에서는 3개의 프레그먼트를 사용하기에 3개를 추가합니다. 

    다음 내용으로 fragment_first.xml, fragment_second.xml, fragment_third.xml 레이아웃 파일을 생성합니다. 


    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <EditText
            android:id="@+id/editText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="EditText" />

    </LinearLayout>




    5. MainActivity.java  메인 액티비티 파일을 추가합니다. 


    package com.tistory.webnautes.viewpager_example;

    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentPagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;

    import me.relex.circleindicator.CircleIndicator;

    public class MainActivity extends AppCompatActivity {
        FragmentPagerAdapter adapterViewPager;


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

            ViewPager vpPager = (ViewPager) findViewById(R.id.vpPager);
            adapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
            vpPager.setAdapter(adapterViewPager);

            CircleIndicator indicator = (CircleIndicator) findViewById(R.id.indicator);
            indicator.setViewPager(vpPager);
        }

        public static class MyPagerAdapter extends FragmentPagerAdapter {
            private static int NUM_ITEMS = 3;

            public MyPagerAdapter(FragmentManager fragmentManager) {
                super(fragmentManager);
            }

            // Returns total number of pages
            @Override
            public int getCount() {
                return NUM_ITEMS;
            }

            // Returns the fragment to display for that page
            @Override
            public Fragment getItem(int position) {
                switch (position) {
                    case 0

                        return FirstFragment.newInstance(0, "Page # 1");
                    case 1:
                        return SecondFragment.newInstance(1, "Page # 2");
                    case 2:
                        return ThirdFragment.newInstance(2, "Page # 3");
                    default:
                        return null;
                }
            }

            // Returns the page title for the top indicator
            @Override
            public CharSequence getPageTitle(int position) {
                return "Page " + position;
            }

        }
    }




    6. 프레그먼트를 위한 파일 3개를 추가합니다. 클래스 이름만 다른  동일한 코드입니다.


    FirstFragment.java


    package com.tistory.webnautes.viewpager_example;

    import android.os.Bundle;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.EditText;


    public class FirstFragment extends Fragment {
        // Store instance variables
        private String title;
        private int page;

        // newInstance constructor for creating fragment with arguments
        public static FirstFragment newInstance(int page, String title) {
            FirstFragment fragment = new FirstFragment();
            Bundle args = new Bundle();
            args.putInt("someInt", page);
            args.putString("someTitle", title);
            fragment.setArguments(args);
            return fragment;
        }

        // Store instance variables based on arguments passed
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            page = getArguments().getInt("someInt", 0);
            title = getArguments().getString("someTitle");

        }

        // Inflate the view for the fragment based on layout XML
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_first, container, false);
            EditText tvLabel = (EditText) view.findViewById(R.id.editText);
            tvLabel.setText(page + " -- " + title);
            return view;
        }
    }




    SecondFragment.java


    package com.tistory.webnautes.viewpager_example;

    import android.os.Bundle;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.EditText;


    public class SecondFragment  extends Fragment {
        // Store instance variables
        private String title;
        private int page;

        // newInstance constructor for creating fragment with arguments
        public static SecondFragment newInstance(int page, String title) {
            SecondFragment fragment = new SecondFragment();
            Bundle args = new Bundle();
            args.putInt("someInt", page);
            args.putString("someTitle", title);
            fragment.setArguments(args);
            return fragment;
        }

        // Store instance variables based on arguments passed
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            page = getArguments().getInt("someInt", 0);
            title = getArguments().getString("someTitle");
        }

        // Inflate the view for the fragment based on layout XML
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_second, container, false);
            EditText tvLabel = (EditText) view.findViewById(R.id.editText);
            tvLabel.setText(page + " -- " + title);
            return view;
        }
    }




    ThirdFragment.java


    package com.tistory.webnautes.viewpager_example;

    import android.os.Bundle;
    import androidx.fragment.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.EditText;


    public class ThirdFragment  extends Fragment {
        // Store instance variables
        private String title;
        private int page;

        // newInstance constructor for creating fragment with arguments
        public static ThirdFragment newInstance(int page, String title) {
            ThirdFragment fragment = new ThirdFragment();
            Bundle args = new Bundle();
            args.putInt("someInt", page);
            args.putString("someTitle", title);
            fragment.setArguments(args);
            return fragment;
        }

        // Store instance variables based on arguments passed
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            page = getArguments().getInt("someInt", 0);
            title = getArguments().getString("someTitle");
        }

        // Inflate the view for the fragment based on layout XML
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_second, container, false);
            EditText tvLabel = (EditText) view.findViewById(R.id.editText);
            tvLabel.setText(page + " -- " + title);
            return view;
        }
    }





    참고


    https://guides.codepath.com/android/viewpager-with-fragmentpageradapter 


    https://github.com/ongakuer/CircleIndicator




    포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
    댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

    여러분의 응원으로 좋은 컨텐츠가 만들어집니다. 지금 본 내용이 도움이 되었다면 후원 또는 유튜브 구독 부탁드립니다. 감사합니다 : )

    유튜브 구 독 하 기
    후 원 하 기


    댓글 10

    • rc8051 2019.03.18 16:30


      감사합니다, 한 개도 모르는 제가해도 잘 되네요~*~*~*

    • noonsong 2019.04.30 00:22


      attribute ci_drawble 이 not found로 에러 뜨는데 무슨 이유이신지 아나요? error: failed linking file resource 입니다..ㅠㅠ

    • ㅇㅇ 2019.05.07 11:14


      안녕하세요!
      // Returns the fragment to display for that page
      @Override
      public Fragment getItem(int position) {
      switch (position) {
      case 0:

      return FirstFragment.newInstance(0, "Page # 1");
      case 1:
      return SecondFragment.newInstance(1, "Page # 2");
      case 2:
      return ThirdFragment.newInstance(2, "Page # 3");
      default:
      return null;
      }
      }
      이 코드에서 문자열을 다른데서 받아오고 싶은데 어떻게 하면 좋을까요?
      "Page # 1"말고 다른 String을 받아오고싶어요..ㅠㅠ..

    • lingu 2019.05.16 17:01


      안녕하세요 각 fragment에서 First Second Third Fragment.java 대신 이미 만들어놓은 다른 클래스를 실행시키고 싶습니다. 어떻게 하면 좋을까요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.16 17:09 신고


        다음 부분을 만들어놓은 프래그먼트로 대체하면 됩니다.

        @Override
        public Fragment getItem(int position) {
        switch (position) {
        case 0:

        return FirstFragment.newInstance(0, "Page # 1");
        case 1:
        return SecondFragment.newInstance(1, "Page # 2");
        case 2:
        return ThirdFragment.newInstance(2, "Page # 3");
        default:
        return null;
        }
        }

    • Curiosity 2019.10.12 16:29


      안녕하세요 dependency에 implementation 'me.relax:circleindicator:1.2.2' 를 추가해도
      ERROR: Failed to resolve: me.relax:circleindicator:1.2.2
      Show in Project Structure dialog
      Affected Modules: app
      같은 에러가 뜨네요.. 어떻게 해야 고칠수 있을까요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.12 18:59 신고


        implementation 'me.relax:circleindicator:1.2.2'를 추가한 후 Sync Now를 클릭했나요?

        현재 포스팅을 androidx 용으로 바꾸어 테스트를 해서 수정해놓았습니다.

Designed by Tistory.