안녕하세요. 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 해도 무방하다.
이젠 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효과를 넣는 거 까지 해보았았습니다.
위를 잘 따라 오셨다면, 아래의 파일은 필요가 없으리라고 믿습니다.
마지막화면까지 완성된 소스코드이며 색상코드는 약간 변경하였습니다~
꽤 긴글이 되었는데 여러분도 한번 천천히 이해하면서 해보시기 바랍니다~