Android/Android ( JAVA )

Android (일곱번째 수업 - Fragment와 TapLayout)

Bin's. 2018. 10. 4. 04:48




Fragment와 TapLayout


먼저 Fragment 란? 


Android 3.0 (API 레벨 11) 에서 Fragment 가 소개 되었습니다.

Fragment는 보통 하나의 Activity안에 여러 UI를 구성할 때 이용할 수 있습니다. 


TapLayou에 적용한 Fragment


이것처럼 Fragment를 사용해서 UI 를 쉽게 넘길수 있습니다.


즉 프래그먼트란 

재사용 가능한 유저 인터페이스를 생성하기 위한 새로운 컴포넌트라고 볼 수 있습니다.


 단 Fragment는 자신만의 레이아웃을 이용하여 화면에 UI 를 보여줄 수 있습니다


하지만 혼자 독자적으로 동작할 수 없으며, 

Fragment 라이프 사이클은 자신이 포함된 Activity 라이프 사이클의 영향을 받습니다.




TabLayout 을 알아보자


Tab 은 상위 탐색 수단 및 앱 내의 컨텐츠를 그룹화 할 수단으로 흔히 사용되고 있습니다. 

디자인 라이브러리의 TabLayout 은 고정 탭을 지원합니다.

많을 경우시 스크롤 이 지원됨.


TabLayout 에 Tab을 눌러 화면 전환


이렇게 Fragment를 전환할수있습니다

하지만 이번예제에선 ViewPager 를 사용해서 슬라이딩 해도

Fragment가 전환이됩니다.



예제설명 - TabLayout 을 이용한 Fragment 전환


먼저 TabLayout 을 MainActivity.xml 에 추가 해줍시다.


중요! Design Support Library 를 추가해줘야합니다.

하지만 안드로이드 3.2 버전이 정식 릴리즈가 되어

dependencies {
implementation 'com.google.android.material:material:1.0.0'
}

meterial 를 dependencies 에 추가해주면 됩니다.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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">

<com.google.android.material.tabs.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@android:color/white"
>
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:layout_below="@+id/tab"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</androidx.viewpager.widget.ViewPager>
</RelativeLayout>


여기서 Fragment 전환을 좀더 쉽게 하기위해서

VIewPager (슬라이딩으로 Fragment 변환) 를 추가 해줬습니다.


그리고 여기서 중요한점은 Fragment 의 View 를 띄어줄

ViewPager 가 TabLayout 밑에 있어야만 탭을 눌렀을시 작동이 됩니다.




자이제 Fragment 를 만드는 법을 알아봅시다.


app -> New -> Fragment -> Fragment (Blank)


이 방식으로 Fragment 를 추가해 주시면 됩니다.


사용할 Tab 에 대한 Fragment 를 만들때 저는 fragment_tab1.xml 을 만들었는데 

Fragment 를 만드는 이름에 따라 달라집니다.

먼저 Fragment 의 xml 코드를 보자면 


<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".Tab1">

<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:text="@string/Fragment1"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
/>
</RelativeLayout>

Fragment 의 xml 에는 Activity의 xml 과 같습니다.

Fragment 를 확인해주기 위해 TextView 를 사용해줬습니다

text 는 @string/Fragment1 를 참조했는데 내용을 보겠습니다.




string.xml

<string name="Fragment1">Fragment1</string>
<string name="Fragment2">Fragment2</string>
<string name="Fragment3">Fragment3</string>

 이런식으로 각 Fragment 에 띄어줄 내용을 참조했습니다.



이제 Fragment 의 class 파일을 보면


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


public class Tab1 extends Fragment {
View view;
public Tab1() {
// Required empty public constructor
}


public static Tab1 newInstance() {
Tab1 tab1 = new Tab1();
return tab1;
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_tab1, container, false);
return view;
}

}

Fragment 를 상속을 받습니다.

위에 형식대로 Fragment 를 만들게되면 다양한 메서드가

존재할거입니다 하지만 사용할 메서드만 

남겨두고 지워주도록 합시다.


newInstance() 는

Class의 객체를 기초로 그 Class가 표시하고 있는 

클래스의 객체를 만들 수 있습니다 = (인수 없는 생성자가 호출된다).


즉 위에 있는 Tab1() 생성자가 호출이됩니다.

그뒤에 Tab1 타입인 tab1 을 만들어줘 return 으로 반환을 해줍니다.

그리고 onCreateView 에는 Activity의 onCreate 와 비슷한데


Fragment 의 UI 가 화면에 그려지는 시점에 호출됩니다. 

XML  Layout을 inflate하여 Fragment를 위한 View를 생성하고 

fragment_tab1 에 View를 Activity에게 리턴해야 합니다. 

 그리고 view 를 return 해줬다면 Fragment 를 성공적으로 만들었습니다.


이 예제에서는 총 3개의 Tab이 사용될것이 때문에 같은 방식으로 Fragment 를 3개 만들어줍시다.




이제 Fragment 를 위한 Adapter 를 만들어줍시다


import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;

public class FragmentAdapter extends FragmentPagerAdapter {

public FragmentAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int position) {
switch (position){
case 0:
return Tab1.newInstance();
case 1:
return Tab2.newInstance();
case 2:
return Tab3.newInstance();
default:
return null;
}
}
@Override
public int getCount() {
return 3;
}
}

이 코드를 간단히 설명하자면 

Fragment 의 interface 를 전환 해주기 위해 

2개의 메서드를 Override 해주는데요


먼저 getItem() 메서드를 보자면 매개변수론 position 을 받는데요

그밑에 switch 문을 사용해 return 해줄 Tab의  newInstance() 메서드를 호출해 

해당 Tab 을 return 해줍니다


물론 index 값은 0 부터 시작하니 0, 1, 2 로 해주시면됩니다.

그리고 Tab이 더이상 없으면 default 로 null 를 return 해줍니다.


이제 getCount() 메서드는 간단합니다. 

return 해줄 Tab의 갯수를 return 해주면 됩니다 .

즉 Item의 갯수를 return 해주면 됩니다 .

 



이제 TabLayout 을 사용하기 위해서 

 activity_main.xml 의 Class 작성해줍시다.


MainActivity.java


import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;

import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.tabs.TabLayout;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

private TabLayout tabLayout;
private ArrayList <String> tabNames = new ArrayList<>();

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

loadTabName();
setTabLayout();
setViewPager();

}

@TargetApi(Build.VERSION_CODES.N)
private void setTabLayout(){
tabLayout = findViewById(R.id.tab);
tabNames.stream().forEach(name ->tabLayout.addTab(tabLayout.newTab().setText(name)));
}

private void loadTabName(){
tabNames.add("1");
tabNames.add("2");
tabNames.add("3");
}

private void setViewPager() {
FragmentAdapter adapter = new FragmentAdapter(getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.viewPager);
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {

}

@Override
public void onTabReselected(TabLayout.Tab tab) {

}
});
}
}

마지막으로 이 코드를 보면 

사용할 TabLayout 의 대한 객체랑 Tab 의 이름을 저장할 객체인 tabNames 를 

ArrayList 객체로 만들어줬습니다.


이제 onCreate() 메서드의 내용을 보면 

loadTabName() 메서드를 호출하는데 

이 메서드 내용은 아까 만들어둔 tabNames 에 add() 메서드를 이용해

string 형태로 저장을 합니다.


저는 add 메서드를 이용해 Tab 의 이름을 차례대로 저장해줬습니다.


이제 다음 메서드인 setTabLayout() 메서드는 

위에 이러한코드가있는데요

@TargetApi(Build.VERSION_CODES.N)

이코드는 Android 플랫폼 별 버전으로 빌드를 한다는 코드인데요

Build.VERSION_CODES.N 은 

Api 레벨 24 인 안드로이드 7.0 Nougat 버젼으로 빌드한다는 코드입니다


이제 메서드 내용을 보면 tabLayout 의 객체에 tab 이란 id를 대입해주는데요.

tab 이란 id 를 가지고 있는 위젯은 위에 activity_man.xml 코드에

TabLayout 의 id 를 대입해줍니다.


그리고 

tabNames.stream().forEach(name ->tabLayout.addTab(tabLayout.newTab().setText(name)));

이 코드는 tabName 을 tabLayout 에 setText() 이용해 Tab 의 이름을 설정해줍니다.


마지막으로 setViewPager() 메서드를 보자면

먼저 Adapter 객체를 만들어 줍니다.

그리고 ViewPager 의 객체를 만들어 ViewPager 의 id 를 대입해줍니다.

그리고 viewPager의 setAdapter() 메서드를 이용해 만들어준 Adapter 객체인 adapter 를 셋팅해줍니다.


그리고 

addOnPageChangeListener()를 이용해 

스크롤시 ViewPager 가 작동하도록 해주고


@Override
public void onTabSelected(TabLayout.Tab tab) {

viewPager.setCurrentItem(tab.getPosition());

}

메서드를 이용해 탭을 눌렀을때 해당 Fragment 로 넘어가기위해 

setCurrentItem() 메서드를 이용해 tab의 Position 을이용해 

해당하는 Tab 을 누르면 viewPager 가 해당 Fragment 로 넘어가게 된다.!



이상으로 최종 완성된 예제의 모습이다


최종



굳 :)