Bucket Place/Android

[Android] ViewPager / ViewPager TabView효과 주기

Cloud Travel 2014. 3. 20. 13:46

안녕하세요. Bucket Place의 개발자 Cloud Travel입니다.

오늘은 저번에 언급한 Fragments를 이용하여 Tabs메뉴와 ViewPager를 연동하는 법에서 포스팅하도록 하겠습니다.


처음으로 해야할 일은 프로젝트를 생성해주셔야 겠죠...?

프로젝트를 생성한 뒤에는 해야 할 일이 있습니다. 2.2 또는 2.3 (허니컴 이전)을 최저 타겟으로 잡고 개발을 할 경우에는 ViewPager와 Fragment를 사용하기 위해서는 android-support-v4.jar 라이브러리를 추가해주셔야 합니다.

※ android-support-v*시리즈는 허니컴 이후에 나온 기술을 이전에서도 사용가능하게 해주는 라이브러리들 입니다.


※ Android project에 외부 라이브러리를 추가하는 방법

 1. Project 최상위 폴더에 libs 폴더를 생성후 library를 복사해줍니다.

   

 2. 프로젝트 이름을 우클릭 한뒤 property 메뉴를 클릭합니다.

 3. 왼쪽 카테고리에서 Java Build Path 를 선택합니다.

 4. 오른쪽 화면텝에서 Libraries 를 선택합니다.

 5. 오른쪽 화면 버튼에서 Add External JARs...를 클릭해줍니다.

 6. 경로를 찾아서 추가를 시켜 준다.

   

 - 현재 사용할  android-support-v4.jar 의 위치는 android-sdk\extras\android\support 폴더 내에 있다고 한다.

 - 없다면 다음의 파일을 다운 받아서 include 해도 무방하다. 


android-support-v4.jar


이젠 ViewPager와 Fragment Tabs를 만들 준비가 모두 끝났다.

처음으로 만들 것은 ViewPager이며, 이곳에 Fragment Tabs를 추가하는 방식으로 가도록 하겠다.


* ViewPager 생성하기.

 - 다음의 단계를 천천히 따라하시다 보면 당신도 손쉽게 ViewPager를 생성할 수 있습니다.

 1. MainActivity를 Activity에서 상속 받는 것이 아닌 FragmentActivity에서 상속 받는 것으로 변경하도록 합시다.

   - FragmentActivity를 생성해야 아래서 Fragment를 자유롭게 사용가능한 것 같습니다.

   ※ 자동 import시 supprot.v4.fragment  인가 그냥 fragment인가를 물을 때가 있는데,

     위에서 말했듯이 min-sdk가 낮다면 support.v4.* 을 import해주셔야 합니다.


/* MainActivity.java */ 

public class MainActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}


 2. MainActivity의 레이아웃에 ViewPager를 추가해주셔야 합니다.

   ※ ViewPager는 허니컴 이후에 나온 기술로 외부 라이브러리에서 가져오므로 명확하게 위치를 명시해주셔야 합니다.

 <!-- activity_main.xml -->
<RelativeLayout 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">

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:requiresFadingEdge="horizontal" />

</RelativeLayout>


 3. ViewPager와 연동시킬 페이지를 생성해줍니다. 저의 경우 3개의 페이지를 생성하도록 하였습니다.

  - 각각의 이름을 Page1Activity.java / Page2Activity.java / Page3Acitivity.java 로 설정하였습니다.

  - 이에 따른 xml파일은 activity_page1.xml / activity_page2.xml / activity_page3.xml 로 설정하였습니다.

  - 각각의 Activity를 Fragment에서 상속받는 것으로 변경, onCreate메소드를 변경, onCreateView메소드를 생성해야합니다.

/* Page1Activity.java */
public class Page1Activity extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
   
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // 어떤 레이아웃에 정의 되있는지 선택해주셔야 합니다!

        RelativeLayout layout = (RelativeLayout)inflater.inflate(R.layout.activity_page1, container, false);

        // 이곳에 layout.(widget) 형식으로 Fragment의 행동을 정의해줍니다.
        return layout;
    }
}

 ※ 잠깐! Fragment에 대한 소스코드를 보고갈가요??

 - Fragment와 Activity의 차이(소스코드상)가 무엇일가요?

  ~ setContentView(R.layout.activit_page1); 의 삭제가 가장 눈에 띕니다.

  ~ 간략히 정리해보겠습니다.

   + Fragment는 FragmentActivity에 종속되는 하나의 부품적인 요소이다.

   + FrgmentActivity에 View가 정의 되있기 때문에  Fragment에서는 View를 정의 할 수 없다.(setContentView 삭제이유)

   + Fragment는 자신의 레이아웃을 생성하여 FragmentActivity로 전달하여 FragmentActivity의 View에 붙이게 됩니다.
      (public View onCreateView()의 존재 이유)


 - 1번 페이지는 버튼을 생성하여 버튼을 클릭시 토스트바를 나오게 설정해보았고,

   2번 페이지는 검정색 바탕화면에 횐색글씨로 글씨가 써있는 페이지를, 3번 페이지는 빈페이지로 하도록 하였습니다.

   (소스코드는 1번페이지에 대해서만 보도록 하겠습니다.)

/* Page1Activity.java */
public class Page1Activity extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
   
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
       
        LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.activity_page1, container, false);

        Button testBtn = (Button) layout.findViewById(R.id.page1Btn);
        testBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(getActivity(), "첫번째 페이지입니다.", Toast.LENGTH_SHORT).show();
            }
        });
        return layout;
    }
}

================================================================

<!-- activity_page1.xml  -->

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

    <Button
        android:id="@+id/page1Btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Page1" />

</RelativeLayout>


 4. 이젠 MainActivity를 수정하여 ViewPager를 달도록 합시다.

  - 소스코드에 주석으로 설명이 되어있으며, 주의 할 곳은 색상을 주었습니다.

/* Main Activity */
public class MainActivity extends FragmentActivity {
   
    private int NUM_PAGES = 3;        // 최대 페이지의 수
   
    /* Fragment numbering */
    public final static int FRAGMENT_PAGE1 = 0;
    public final static int FRAGMENT_PAGE2 = 1;
    public final static int FRAGMENT_PAGE3 = 2;
   
    ViewPager mViewPager;            // View pager를 지칭할 변수
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        // ViewPager를 검색하고 Adapter를 달아주고, 첫 페이지를 선정해준다.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(new pagerAdapter(getSupportFragmentManager()));
        mViewPager.setCurrentItem(FRAGMENT_PAGE1);
    }
   
    // FragmentPageAdater : Fragment로써 각각의 페이지를 어떻게 보여줄지 정의한다.
    private class pagerAdapter extends FragmentPagerAdapter{

        public pagerAdapter(android.support.v4.app.FragmentManager fm) {
            super(fm);
        }

        // 특정 위치에 있는 Fragment를 반환해준다. 몇번째 화면에 어떤 Fragment가 올지 정해준다.
        @Override
        public Fragment getItem(int position) {
           
            switch(position){
                case FRAGMENT_PAGE1:
                    return new Page1Activity();
                case FRAGMENT_PAGE2:
                    return new Page2Activity();
                case FRAGMENT_PAGE3:
                    return new Page3Activity();
                default:
                    return null;
            }
        }
       
        // 생성 가능한 페이지 개수를 반환해준다.
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return NUM_PAGES;
        }
    }   
}


 5. 중간 결과물입니다. ViewPager를 완성한 상태이죠!!

 



* ViewPager를 TabView처럼 변경해보자!!

 - 목표 : 앞서 완성된 ViewPager의 Main을 약간 수정하여 TabView효과를 가미해보자!

 1. MainActivity의 Layout을 변경해보자. Tab이라면, Tab효과를 가질 버튼이 필요할 것이다.

   - activity_main.xml을 수정한다. 텝효과를 추가시킬 버튼을 위에 생성해주었다.

<!-- 수정된 activity_main.xml -->
<RelativeLayout 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">
    <!-- 상단 버튼 추가 -->
    <LinearLayout 

        android:id="@+id/menuIcon"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/Page1Btn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Page1" />
        <Button
            android:id="@+id/Page1Btn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Page2" />
        <Button
            android:id="@+id/Page3Btn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Page3" />
    </LinearLayout>
   
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:requiresFadingEdge="horizontal"
        android:layout_below="@id/menuIcon" />

</RelativeLayout>


2. MainActivity에 각각의 버튼을 참조하여 클릭이벤트를 작성해준다.

  - ViewPager.setCurrentView(int position) 함수를 이용하여서 손쉽게 현재 화면의 Fragment를 변경할 수 있다.

  ※ 버튼 여러개에 리스너를 다는 것보다 Activity에 리스너를 달아서 이용하면 손쉽게 적용이 가능해진다.

 /* 수정된 Main Activity */
public class MainActivity extends FragmentActivity implements OnClickListener {
   
    private int NUM_PAGES = 3;        // 최대 페이지의 수
   
    /* Fragment numbering */
    public final static int FRAGMENT_PAGE1 = 0;
    public final static int FRAGMENT_PAGE2 = 1;
    public final static int FRAGMENT_PAGE3 = 2;
   
    ViewPager mViewPager;            // View pager를 지칭할 변수
   
    Button page1Btn, page2Btn, page3Btn;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        // ViewPager를 검색하고 Adapter를 달아주고, 첫 페이지를 선정해준다.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(new pagerAdapter(getSupportFragmentManager()));
        mViewPager.setCurrentItem(FRAGMENT_PAGE1);
       
        page1Btn = (Button) findViewById(R.id.Page1Btn);
        page1Btn.setOnClickListener(this);
        page2Btn = (Button) findViewById(R.id.Page2Btn);
        page2Btn.setOnClickListener(this);
        page3Btn = (Button) findViewById(R.id.Page3Btn);
        page3Btn.setOnClickListener(this);
       
    }
   
    // FragmentPageAdater : Fragment로써 각각의 페이지를 어떻게 보여줄지 정의한다.
    private class pagerAdapter extends FragmentPagerAdapter{

        public pagerAdapter(android.support.v4.app.FragmentManager fm) {
            super(fm);
        }

        // 특정 위치에 있는 Fragment를 반환해준다.
        @Override
        public Fragment getItem(int position) {
           
            switch(position){
                case 0:
                    return new Page1Activity();
                case 1:
                    return new Page2Activity();
                case 2:
                    return new Page3Activity();
                default:
                    return null;
            }
        }
       
        // 생성 가능한 페이지 개수를 반환해준다.
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return NUM_PAGES;
        }
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
       
        switch(v.getId()){
            case R.id.Page1Btn:
                mViewPager.setCurrentItem(FRAGMENT_PAGE1);
                break;
            case R.id.Page2Btn:
                mViewPager.setCurrentItem(FRAGMENT_PAGE2);
                break;
            case R.id.Page3Btn:
                mViewPager.setCurrentItem(FRAGMENT_PAGE3);
                break;
        }
    }   
}


 3. 결과 화면

  - 화면1에서  Page2 버튼을 클릭했을 경우

   


* 추가적인 Tips!!

 - ViewPager에는 다음의 리스너를 달 수 있습니다.

  > OnPageChangeListener : 이 리스너는 ViewPage에서 특정 화면이 선택되거나, 화면이 스크롤 되거나... 등의 상태를 파악가능!

  > 이를 이용하여 버튼의 배경을 꾸밀 수 있겠죠...?

 - 아래의 화면은 제가 텝 버튼에 칼라를 주어서 설정한 것입니다. selected status를 이용하여서 만들었죠...

  

  - 이쪽 부분에 대한 간략한 소스코드입니다.

      mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
           
            @Override
            public void onPageSelected(int position) {
                // TODO Auto-generated method stub
                page1Btn.setSelected(false);
                page2Btn.setSelected(false);
                page3Btn.setSelected(false);
               
                switch(position){
                    case 0:
                        page1Btn.setSelected(true);
                        break;
                    case 1:
                        page2Btn.setSelected(true);
                        break;
                    case 2:
                        page3Btn.setSelected(true);
                        break;
                }
            }
            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
                // TODO Auto-generated method stub
               
            }
           
            @Override
            public void onPageScrollStateChanged(int arg0) {
                // TODO Auto-generated method stub
            }
        });
       
        page1Btn.setSelected(true);


위에서 주저리주저리 하면서 ViewPager와 ViewPager에 Tab효과를 넣는 거 까지 해보았았습니다.

위를 잘 따라 오셨다면, 아래의 파일은 필요가 없으리라고 믿습니다.


Blog.zip


마지막화면까지 완성된 소스코드이며 색상코드는 약간 변경하였습니다~

꽤 긴글이 되었는데 여러분도 한번 천천히 이해하면서 해보시기 바랍니다~