본문 바로가기

FrontEnd/Android 기초

[Android] Fragment 프래그먼트

반응형

Fragment이란

 

파편, 조각이라는 뜻을 가진 Fragment는 하나의 Activity로 여러개의 화면을 구성하도록 해준다. 지금까지 하나의 Activity는 하나의 화면을 구성한다고 배웠지만, Fragment를 활용하면 좀 더 쉽고 효율적으로 많은 화면을 구성할 수 있게 된다. 화면을 각각 분할해서 독립적인 코드로 구성할 수 있게 도와주는 것이 Fragment이다. Fragmen는 Activity가 설정한 화면 위에 존재하고, Activity처럼 Fragment도 자신만의 화면을 구성하는 xml파일을 가지고 있다. 따라서 여러개의 Fragment를 만들고 Activity위에 Fragment를 교체하면 하나의 Activity를 가지고 여러화면을 제작할 수 있다. Fragment는 뷰는 아니지만, 뷰처럼 뷰그룹(Layout)안에 들어갈 수 있고, Activity처럼 LifeCycle(생명주기)도 가지고 있다. 

  

화면(뷰)이 하나만 필요할 때는 Fragment를 사용하지 않는다.

Fragment는 2개 이상의 화면을 빠르게 이동한다든지 탭으로 구성된 화면의 자연스러운 움직임을 구현할 때 주로 사용된다. 따라서 1개의 액티비티에 1개의 뷰만 필요한 구조라면 Fragment를 사용하지 않는것이 바람직하다.

Fragment 또한 하나의 모듈로써 동작하기 때문에 생성에 따른 자원이 낭비되고, 액티비티와 별개의 생명주기를 갖고 있어서 ㅓ상황에 따라 생명 주기 관련 코드를 액티비티와 Fragement 양쪽에 작성해야할 수도 있다.

 

Fragment 화면 띄우는 방법

 

1. activity_main.xml의 레이아웃을 RelativeLayout으로 바꾼다.

(typing 중)

 

(수정 후)

 

2. activity_main.xml의 DesignView로 가서, BottomNavigationView 선택

(id는)

 

3. id,width,height,align,background 설정

id : bottomNavigationView

layout_width = match_parent

layout_height = wrap_content

layout_alignParentBottm = true

background = #ffffff

 

4. 왼쪽의 Resource Manager 탭 

- 상단/…(더보기)의 Navigation 항목 선택

- 상단의 +버튼 클릭 및 Navigation Resource File 클릭

 

5. 파일명: my_nav로 하고 OK 클릭

 

6. Add Project Dependency 경고창에서 OK 클릭

(간혹 안뜨는 경우도 있기는 한데, 그럴 때는 Android Studio를 닫았다가 재실행하면 된다.)

 

7. 클릭하면 바로 my_nav.xml로 들어가진다. Design 탭 클릭후, 상단 New Destination - Create new destination을 클릭한다.

 

8. Fragment(Blank) 선택

 

9. Fragment 이름 설정: FirstFragment

 

10. 총 3개의 Fragment를 같은 방법으로 만든다: SecondFragment, ThirdFragment

 

11. activity_main에서, NavHostFragment를 끌어다놓는다.

 

12. 기존에 만들어놓은 my_nav 선택

 

13. 이 Fragment의 위치를 지정해준다: layout_above: @id/bottomNavigationView

-> 밑에 탭이 보일수 있도록 해준다.

-> MainActivity안에서 Fragment만 바뀌는 것. 즉, FirstFragment, SecondFragment, ThirdFragment가 바뀌는 것. 이부분은 Fragment에서 각각 설정해줄것이다.

 

14. 각 3개의 Fragment의 텍스트를 각 표시해준다.

FirstFragment: 첫번째

SecondFragment: 두번째

ThirdFragment: 세번째

 

 

Fragment 메뉴 만들기

15. Resource Manager에서 …(더보기)에서 menu선택 및 +버튼을 눌러 Menu Resource File을 선택한다.

 

16. 파일명은 bottom_menu로 한다.

 

17. Design 뷰에서, Menu Item을 3개 추가한다 -> 탭을 3개 만들것이다.

 

18.탭에 넣을 아이콘 필요: Resource Manager에서 drawable 선택

 

19. Clip Art에서 원하는 아이콘 선택, Name 및 컬러 정해주고, 3개 만든다.

 

20. bottom_menu.xml에서 아까 추가한 각 Menu Item에서 id, title 및 icon을 설정한다.

-> id는 각 Fragment의 Id와 같게 셋팅한다. 

 

21. activity_main.xml에서 bottomNavigationView에 menu 검색 및 bottom_menu 선택, OK

 

하단 부분에 방금 menu에서 셋팅한 아이콘과 타이틀이 표시된다. 

 

22. 탭이 4개 이상되면, 타이틀이 보이지 않을 때가 있는데, activity_main.xml에서 아래처럼 하면, 아이콘과 타이틀 표시가 가능하다.

 

Fragment코드 작성

 

1. MainActivity.java 파일에 들어가서 코드 작성을 한다.

// 액션바 숨기는 코드
// getSupportActionBar().hide();

navigationView = findViewById(R.id.bottomNavigationView);

firstFragment = new FirstFragment();
secondFragment = new SecondFragment();
thirdFragment = new ThirdFragment();
// 프레그먼트 생성, 우리가 만든 파일
// 얘는 findViewbyId가 아니라, 객체생성이다.

navigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { 
     @Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                int itemId = item.getItemId();

                Fragment fragment = null;

                if(itemId == R.id.firstFragment){
                    fragment = firstFragment;

                    getSupportActionBar().setTitle("홈");
                    getSupportActionBar().show();

                } else if(itemId == R.id.secondFragment){
                    fragment = secondFragment;

                    getSupportActionBar().setTitle("친구");
                    getSupportActionBar().show();

                } else if(itemId == R.id.thirdFragment){
                    fragment = thirdFragment;

                    getSupportActionBar().hide();
                }

// 첫번째/두번째/세번째 메뉴(Fragment)를 누르면, 그에 해당하는 Fragment로 전환한다.
// 그리고 해당 프래그먼트의 화면의 액션바를 변경해준다.
// return을 우선 true로 바꾼다.
// 비어있는 Fragment를 하나 만든다: Fragment fragment = null;
// true로 return하게끔, loadFragment함수를 만든다.

                return loadFragment(fragment);
            }
        });
    }

    private boolean loadFragment(Fragment fragment) {
        if(fragment != null){
            getSupportFragmentManager()
                    .beginTransaction()
                    .replace(R.id.fragment, fragment)
                    .commit();
            return true;
        }
        return false;
    }
// 프래그먼트가 비어있지 않으면, 
// getSupportFragmentManager()를 사용해서 FragmentManager 객체를 얻을 수 있으며, 액티비티에 Fragment를 추가, 교체 및 삭제를 할 수 있다. 
// replace(R.id.fragment, fragment): 레이아웃에 삽입되어 있는 프래그먼트와 교체한다.
// .commit(: 모든 작업이 정상적으로 처리되었음을 알려준다.

}

 

2. FirstFragment 파일에 가서, onCreateView에 코드를 작성한다.

 

액티비티가 실행되면 onCreate메소드가 자동으로 실행된다. 프래그먼트 클래스에서는 onCreate메소드를 대신해서 onCreateview메소드를 사용한다. onCreateView의 첫번째 파라미터는 LayoutInflater객체이고, 두번째 Fragment를 담을 뷰그룹이다. Fragment는 setContentView 메소드를 가지고 있지 않다.(setContentView는 Activity의 메소드이다.) 따라서 Fragment에서는 onCreateView에서 XML을 inflate하도록 되어있다.

 

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

   ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_first, container, false);
   return rootView;
}

 

onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)의 파라미터:

- inflater: 레이아웃 파일을 로드하기 위한 레이아웃 인플레이터를 기본으로 제공한다

- container: 프래그먼트 레이아웃이 배치되는 부모 레이아웃이다.(액티비티의 레이아웃)

- savedInstanceState: 상태 값 저장을 위한 보조도구. 액티비티의 onCreate의 파라미터와 동일하게 동작한다.

 

fragement_first.xml에 있는 내용을 inflate하는 과정이다. Fragment가 담길 뷰그룹은 id가 container로 되어있고, 바로 이곳으로 fragment_first.xml파일에 있는 내용들이 inflate 되어 화면을 채우게 된다.

 

3. FirstFragment 파일에서, ReciclerView코드를 작성한다

(사전에 전에 만들었던, model,api,adapter,config 패키지 내용은 다 만들어놓자)

// 화면에 매칭할 멤버변수
    RecyclerView recyclerView;
    MyPostingAdapter adapter;
    ArrayList<Posting> postingList = new ArrayList<>();

    ProgressBar progressBar;
    private int count = 0;
    private int offset = 0;
    private int limit = 25;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_first, container, false);

        progressBar = rootView.findViewById(R.id.progressBar);
        recyclerView = rootView.findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        getNetworkData();

        return rootView;
    }

 

Fragment 자체는 findViewById를 사용할 수가 없기 때문에 ViewGroup 클래스 객체인 rootView를 통해 findViewById를 사용한다. 

 

다른 코드 작성할 때 MainActivity에서 작동하도록 이미 해놨기 때문에 getContext()라고 하면, 내 Fragment가 돌고 있는 Activity를 가르킨다. 해당 프래그먼트가 포함되어있는 액티비티.

Retrofit 통신하는 코드도 MainActivity.this 대신에 getContext() 혹은 getActivity()로 치환한다.

 

  // 처음으로 데이터 가져올때
    void getNetworkData(){

        postingList.clear();
        count = 0;
        offset = 0;

        progressBar.setVisibility(View.VISIBLE);

        Retrofit retrofit = NetworkClient.getRetrofitClient(getContext());
        PostingApi api = retrofit.create(PostingApi.class);

//        SharedPreferences sp = getContext().getSharedPreferences(Config.PREFERENCES_NAME, getContext().MODE_PRIVATE);
        String accessToken = "eyJ0eX********I";

        Call<PostingList> call = api.getMyPosting("Bearer "+accessToken,
                offset,
                limit);
        call.enqueue(new Callback<PostingList>() {
            @Override
            public void onResponse(Call<PostingList> call, Response<PostingList> response) {
                progressBar.setVisibility(View.GONE);
                if(response.isSuccessful()){

                    count = response.body().getCount();

                    postingList.addAll( response.body().getItems() );

                    offset = offset + count;

                    adapter = new MyPostingAdapter(getActivity(), postingList);

                    recyclerView.setAdapter(adapter);

                }else{

                }
            }


반응형