ViewPager 완전정복(일단 만들기)

Posted by ITPangPang
2016.10.28 22:45 안드로이드(android)/ViewPager


ViewPager 완전정복

(일단 만들기)



ㆍ 이번글을 시작으로 ViewPager에 대해 써보려고 합니다.


ViewPager에 대해서 완벽하게 알지는 못하지만..

    완벽하게 알기 위해서 분석하면서 글을 써보려합니다.


ㆍ 이번글에선 가장 기본적인 형태로 Fragment로 구성된

    ViewPager를 만들어보도록 하겠습니다.



시작전에 앞으로 알아볼 내용!


대부분 쓰게 될 내용은

제가 만들던 앱에서 사용했던

ViewPager에 대한 내용과 

나름 삽질하면서

알아냈던 부분이 될 것 같습니다


- 기본적인 형태의 ViewPager(Fragment) 만들기

- setOffscreenPageLimit, setUserVisibleHint에 대해서

setUserVisibleHint를 사용한 예제

- addOnPageChangeListener에 대해서

- VerticalViewPager, HorizontalViewPager 

- 동적인 ViewPager 만들기 - Fragment(x)

- ViewPager에 연결된 Adapter 건드리기


일단 생각나는 내용만

적어봤습니다.


위에 적어놓은 리스트는

무조건 분석글을 쓰도록 하고

추가로 생각나는 부분에 대해서

더 써보겠습니다.


그럼 만들어 보자!!



오늘 만들어 볼 화면입니다


아주 기본적인 형태죠

3개의 페이지로 구성되어있으며

좌우 Swipe를 통하여 페이지 전환

가능합니다.


그리고 위에 버튼 3개를 배치했습니다

(이라고 가정.. 보통 이렇게들 요즘 많이 만드니)


버튼을 눌렀을때 해당 페이지로 이동하는

방법까지 알아보도록 하겠습니다.


디자인은 음..

일단 써보고 시간나면

좀 더 이쁘게 다듬어볼게요


자 먼저 layout부터 만들어 보자!


위 화면을 만들기 위해서는

4개의 layout 파일이 필요합니다


1. MainActivity에 들어가는 layout

(여기서 탭과 Viewpager의 영역을 나눠야겠죠)

2. 첫번째 페이지 Content

3. 두번째 페이지 Content

4.세번째 페이지 Content



[activity_main.xml]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_first"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="첫번째 탭" />

<Button
android:id="@+id/btn_second"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="두번째 탭" />

<Button
android:id="@+id/btn_third"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="세번째 탭" />
</LinearLayout>

<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/ll">
</android.support.v4.view.ViewPager>


</RelativeLayout>


버튼 3개와 ViewPager

이루어져있습니다.


지금은 탭부분을(버튼 3개)

weight로 넣었지만

실제로는 대부분 이미지가

들어가기 때문에 wrap으로 넣겠죠



[fragment_first.xml]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#000000"
>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="30dp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:text="첫번째 페이지"/>

</RelativeLayout>


볼 것도 없죠 TextView 하나

넣어놨습니다.

나머지 2개의 레이아웃도

동일합니다.


[fragment_second.xml]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FF0000"
>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="30dp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:text="두번째 페이지"/>

</RelativeLayout>


[fragment_third.xml]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#1439dc"
>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="30dp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:text="세번째 페이지"/>

</RelativeLayout>


이제 해당 페이지를 다룰 Fragment를 생성해보자!


3개의 Fragment를

만들면 되겠죠?


뭐 내용도 없습니다

위에서 만든 layout과

연결해주면 끝!


[FirstFragment.java]

public class FirstFragment extends Fragment
{
public FirstFragment()
{
}


@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.fragment_first, container, false);
return layout;
}
}


아! 한가지만 봐주세요


public FirstFragment(){

}


이거 꼭 넣어주세요!


Fragment 만들때 빈 생성자는

필수로 만들어주셔야 합니다

(궁금하신 분은 아래 링크를 눌러주세요)


빈 생성자를 필수로 만들어야 되는 이유!



나머지 두번째, 세번째 

Fragment도

완전 동일합니다!


[SecondFragment.java]

public class SecondFragment extends Fragment
{
public SecondFragment()
{
}
@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.fragment_second, container, false);
return layout;
}
}


[ThirdFragment.java]

public class ThirdFragment extends Fragment
{
public ThirdFragment()
{
}
@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.fragment_third, container, false);
return layout;
}
}


이제 MainActivity만 만들면 끝!


벌써 MainActivity만

만들면 끝이 납니다.


뭔가 많이 적긴 했는데

전부 동일한 내용 복붙한거라

어려운 부분은 없었습니다.


메인을 보도록 하겠습니다

(이 부분도 별 내용 없습니다)



[MainActivity.java]

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

vp = (ViewPager)findViewById(R.id.vp);
Button btn_first = (Button)findViewById(R.id.btn_first);
Button btn_second = (Button)findViewById(R.id.btn_second);
Button btn_third = (Button)findViewById(R.id.btn_third);

vp.setAdapter(new pagerAdapter(getSupportFragmentManager()));
vp.setCurrentItem(0);

btn_first.setOnClickListener(movePageListener);
btn_first.setTag(0);
btn_second.setOnClickListener(movePageListener);
btn_second.setTag(1);
btn_third.setOnClickListener(movePageListener);
btn_third.setTag(2);
}

View.OnClickListener movePageListener = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
int tag = (int) v.getTag();
vp.setCurrentItem(tag);
}
};

private class pagerAdapter extends FragmentStatePagerAdapter
{
public pagerAdapter(android.support.v4.app.FragmentManager fm)
{
super(fm);
}
@Override
public android.support.v4.app.Fragment getItem(int position)
{
switch(position)
{
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
case 2:
return new ThirdFragment();
default:
return null;
}
}
@Override
public int getCount()
{
return 3;
}
}
}


메인도 생각보다

길지 않죠?


하나하나씩 보겠습니다.

vp = (ViewPager)findViewById(R.id.vp);
Button btn_first = (Button)findViewById(R.id.btn_first);
Button btn_second = (Button)findViewById(R.id.btn_second);
Button btn_third = (Button)findViewById(R.id.btn_third);

vp.setAdapter(new pagerAdapter(getSupportFragmentManager()));
vp.setCurrentItem(0);


위에 Viewpager와 버튼 초기화하는

부분은 볼 필요 없겠죠


vp.setAdapter(~~)

ViewPager의 Page를

전체적으로 관리해주려면

Adapter가 필요하겠죠

(ViewPager-Adapter 연결)


vp.setCurrentItem(0);

앱이 실행됬을때

첫번째 페이지로 초기화

시키는 부분입니다


private class pagerAdapter extends FragmentStatePagerAdapter
{
public pagerAdapter(android.support.v4.app.FragmentManager fm)
{
super(fm);
}
@Override
public android.support.v4.app.Fragment getItem(int position)
{
switch(position)
{
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
case 2:
return new ThirdFragment();
default:
return null;
}

}
@Override
public int getCount()
{
return 3;
}
}


이 부분도 코드를 보면

알 수 있듯이


Adapter로는

FragmentStatePagerAdapter

사용했습니다

(FragmentPagerAdapter가 아닙니다!)

State가 붙은 Adapter를 사용하는 이유가

있습니다.


FragmentPagerAdapter 문제점




switch(position)

각 포지션값이 들어오면

생성해둔 Fragment Class를

열어주는 부분입니다


getCount()

ViewPager안에 들어가는

Page의 갯수이죠


    btn_first.setOnClickListener(movePageListener);
btn_first.setTag(0);
btn_second.setOnClickListener(movePageListener);
btn_second.setTag(1);
btn_third.setOnClickListener(movePageListener);
btn_third.setTag(2);
}

View.OnClickListener movePageListener = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
int tag = (int) v.getTag();
vp.setCurrentItem(tag);
}
};


마지막으로 버튼 클릭시

해당 페이지로 이동하는 부분입니다.


각 버튼마다 Click리스너를 달아주고

각 페이지 position에 해당되는

int형 값을 Tag값으로 넣어줬습니다.

(이 부분은 굳이 태그 안넣어도 되지만..

코드좀 간결화 시킬겸 써봤습니다..)


Tag부분 이해가 안가시는 분은 아래글을

참고해주세요


setTag, getTag 사용하기


vp.setCurrentItem(tag);

핵심은 이 부분이죠

tag값에 페이지에 해당하는

Position을 넣어주면

해당 페이지로 이동되는

부분입니다


아..

내용은 없는데

동일 코드가 너무 많아서

글이 길어보이네요..

지금 쓰면서도 약간 렉이 있고.

ㅠㅠ


화면 예쁘게 꾸미는 부분은

다음글에서 만들어서 오도록

하죠..


다음번에 쓸 내용에 대해 잠시

써보자면


- setOffscreenPageLimit, setUserVisibleHint에 대해서

이것에 대해 써 볼 예정인데


LifeCycle에 관한 내용이 될 것 같습니다

뭐 onCreateView, onDestroyView 이 정도에

로그 찍어볼 수준이지만..


아시는분은 아실테지만

 ViewPager에서 기본 디폴트는

현재 보이는 페이지 좌우만

생성해놓고 사용하는 구조입니다

(생성해 놓는다!, 좌우만 보인다!

이 두가지가 은근히 초반에 골때립니다.

다음글에서 이것에 관한 개념을 다뤄보겠습니다)

저작자 표시 비영리 변경 금지
신고
이 댓글을 비밀 댓글로
    • 감사
    • 2017.03.01 05:46 신고
    감사합니다 덕분에 간단한 어플리캐이션을 만들 수 있게 되었습니다.
    • ㅠㅠ
    • 2017.03.29 13:55 신고
    incompatible types: FirstFragment cannot be converted to Fragment

    이런 내용의 FirstFragment를 Fragment로 바꿀 수 없다고 뜹니다.ㅠ.ㅠㅠ
    • 음 제 생각에는
      제가 import 하는 부분 코드를 안넣어서
      그런것 같네요

      Fragment 는 종류가 2가지 있는데

      아마 FirstFragment~ThirdFragment까지

      import android.app.Fragment;
      이렇게 되있을 거 같은데
      이걸 삭제하고 다시 아래껄로 넣어보세요
      import android.support.v4.app.Fragment;