프롤로그 참고 - [prologue] 2019 부스트코스 에이스 합격! (안드로이드)

(요약 - 부스트코스 강의를의 단순 요약하는 것보다는, 실질적으로 프로젝트에 도움이 될 핵심포인트들과 꿀팁들 등을 위주로 작성하기로 하였다.)

 

 


< 게 시 글    목 차 >

PJT4에서 구현해야할 화면!!

 

- 프로젝트 4의 핵심 포인트 단 한가지 ! 

  1. 프로젝트4는 ViewPager로 시작해서 ViewPager로 끝난다. 사용법을 간략하게 정리해보자!

+ additional tips 

  1. 기존 영화상세화면은 Activity였으나 이제는 Fragment로 바꿔야한다. 바꿀때의 주의점과 방법에 대하여 알아보자
  2. 어플리케이션 상단의 툴바 투명하게 만드는 방법! app:elevation 속성을 사용하자. 
  3. 영화상세화면에서 다시 영화목록으로 돌아가기 - 뒤로가기버튼을 눌렀는데 앱이 종료된다면?! -  addToBackStack() 사용!
  4. 영화목록화면에서 한 화면에 여러 개의 포스터 보이게 하는방법!(현재 포스터 양옆에 이전,이후 포스터 살짝 보이게하기) (★★) - ViewGroup.setClipToPadding(false) 사용!!

*** 게시글이 길기 때문에 ctrl+f 로 원하는 부분을 찾아서 보자!

 

 

 


프로젝트 4 핵심 포인트 단 한가지 !

 

1. ViewPager 사용법 간단 정리!

1-1: 레이아웃XML파일에 <ViewPager> 태그추가

1-2: ViewPager를 위한 어댑터 정의!

1-3: ViewPager가 들어갈 액티비티/프래그먼트에서 뷰페이저-어댑터 연결

 

 


1-1) 레이아웃XML파일에 <ViewPager>태그 추가

 

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

간-단

 

 


1-2) ViewPager를 위한 어댑터 정의!

 

public class MoviePagerAdapter extends FragmentStatePagerAdapter {

	// 프래그먼트가 저장될 ArrayList<Fragment>
	// 5개의 영화 군도,공조,더킹,레지던트이블,럭키 각각에 대한 프래그먼트가 들어갈 예정!
    ArrayList<Fragment> items = new ArrayList<Fragment>();

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

    public void addItem(Fragment item){
        items.add(item);
    }

    @Override
    public Fragment getItem(int position) {
        return items.get(position);
    }

    @Override
    public int getCount() {
        return items.size();
    }

}

 ViewPager에 사용할 어댑터는 FragmentStatePagerAdapter를 상속하여 만든다.

멤버변수로 ArrayList<Fragment> 를 추가하고, 후에 여기에 들어가있는 Fragment들이 뷰페이저 안에 들어가서 보이게 된다.

 

void addItem(Fragment item) 은 자동으로 제공되는 소스코드가 아니다. 작성하자!

필요에따라 deleteItem() 등을 작성할 수 있겠으나 우선은 addItem()만 작성한다.

 

Fragment getItem(int position), int getCount() 등도 default로 제공되는 코드에는 return null, return 0 등으로 되어있으니 꼭 확인하여 수정하자.

 

 


1-3) ViewPager가 들어갈 액티비티/프래그먼트에서 뷰페이저-어댑터 연결

 

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

	//...


	pager = (ViewPager)rootView.findViewById(R.id.movie_pager);
	pager.setOffscreenPageLimit(3);

	MoviePagerAdapter adapter = new MoviePagerAdapter(getFragmentManager());
        
	for(Movie movie : movies){
		MovieFragment frag = new MovieFragment();
		frag.setMovie(movie);
		adapter.addItem(frag);
	}

	pager.setAdapter(adapter);
        
       
	//...
}

우리는 영화목록 프래그먼트에 ViewPager를 넣을 것이다.

해당 프래그먼트의 onCreateView에서 Adapter 객체를 동적으로 생성한 뒤, 미리 작성해둔 addItem() 메소드를 사용하여

필요한 만큼 프래그먼트를 추가해준다.

마지막에 ViewPager 객체에 어댑터객체를 setAdapter()를 통해 연결시켜주면 끗-!

 

 

 

 

 


+ additional tips 

 

1. 기존 영화상세화면은 Activity였으나 이제는 Fragment로 바꿔야한다.

바꿀때의 주의점과 방법에 대하여 알아보자.

 

PJT3까지는 MainActivity가 영화 상세화면이었다. 하지만 이제 MainActivity에서는 Fragment를 관리하는 코드와, 바로가기 메뉴와 툴바등을 위한 코드만 들어가게된다. 기존 영화상세화면과 관련된 코드들은 복사하여, 새로운 Fragment에 그대로 긁어넣으면 된다.

(편의를 위하여 앞으로 영화상세화면 프래그먼트는 MovieDetailFragment 라고 부르겠다!)

 

그대로 복붙하면 된다. 단, 수정해야할 부분이 두가지있다.(코드 작성방식에 따라 더있을수도..)

(1) Activity의 context를 사용하는 부분에서 →  getApplicationContext() 를 getContext() 또는 (Context)mCallback 등으로 바꾸자. getApplicationContext() 는 액티비티 코드안에서만 사용할 수 있다.

(mCallback는 FragmentCallback의 객체이고, MainActivity가 implement하는 클래스이다...강의를 참고하자)

 

(2) 영화상세화면에서 '작성하기', '모두보기' 버튼을 누르면 startActivityForResult()를 통해 새로운 액티비티를 호출했었다.

Fragment내에서는 해당 메소드 호출이 불가하다. Fragment가 올라가있는 액티비티(지금의 경우 MainActivity)에서 호출을 해야하고, 이를위하여 FragmentCallback의 메소드를 활용한다.

(MainActivity가 해당 인터페이스를 implement함으로써 액티비티↔프래그먼트 의 소통이 가능하다. 강의참고!)

(강의: 부스트코스 안드로이드 - 4. 화면 내비게이션 - 4.7 Summary - (1) 내용 정리 - 두번째 동영상)

(https://www.edwith.org/boostcourse-android/lecture/20487/)

 

(기존코드) (1),(2) 적용 前

작성하기_버튼.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(getApplicationContext(), WriteReviewActivity.class);
        float rating = ratingbar.getRating();
        intent.putExtra("rating", rating);

        startActivityForResult(intent, REQUEST_WRITE_BUTTON_CLICKED);
    }
});

(수정 후 코드) (1),(2) 적용 後

/* FRAGMENT의 코드! */
작성하기_버튼.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
    	mCallback.onCommand("커맨드", "데이터");
    }
});

/* MainActivity는 위에서 사용한 onCommand() 메소드를 implement 한다. MainActivity의 onCommand()는 다음과 같다.(예시) */
@Override
public void onCommand(String command, String data) {    
    if(command.equals("커맨드")){
    // 액티비티를 띄우는 경우 
    startActivity();
    // 프래그먼트를 띄우는 경우 
    getSupportFragmentManager().beginTransaction().replace(...).commit();   
    }
}

 

 

 

 

2. 어플리케이션 상단의 툴바가 투명해진다.

<AppBarLayout>app:elevation 속성을 사용하자!

 

우리가 지금 하려는 작업! 액션바의 경계를 없애보자.

프로젝트 4의 요구사항(결과물 화면캡쳐)를 보면 위 사진의 오른쪽과 같이, 액션바와 아래 프래그먼트의 경계선이 없다.

이는 프로젝트4의 강의에서 알려주지 않는 내용으로, 스스로 구글링을 통해 방법을 찾아내야한다.

여러가지 방법이 있을 수 있으나, 나는 액션바(혹은 툴바)를 담고있는 activity_main.xml 내에서

<android.support.design.widget.AppBarLayout> 의 속성을 수정하였다.

 

<AppBarLayout> 내에서

android:background="@android:color/transparent" 로 액션바가 투명이 될 수 있도록 하였고,

app:elevation="0dp" 를 통해 액션바에 적용이되는 그림자효과(?)가 없어지도록 하였다.

<android.support.design.widget.CoordinatorLayout
    android:background="@drawable/main_background"
    ...> 

    <android.support.design.widget.AppBarLayout
        android:background="@android:color/transparent"
        app:elevation="0dp"
        ...>

        <android.support.v7.widget.Toolbar ... />

    </android.support.design.widget.AppBarLayout>

</android.support.design.widget.CoordinatorLayout>

위와같이 xml를 수정하면, <AppBarLayout>은 투명해지고, 그렇게함으로써 그동안 가려져있었던,

상위태그 <..CoordinatorLayout>에서 설정해놓은 backgroud가 보이게된다.

(@drawable/main_background 는 위에서 보이는것과 같이 그라데이션이 적용된 사진이다. 따로 만들필요없이 PJT4에서 제공해준다!)

 

 

 

 

3. 영화상세화면에서 다시 영화목록으로 돌아가기.

뒤로가기버튼을 눌렀는데 앱이 종료된다면?! - addToBackStack() !

 

 

영화목록화면(MovieListFragment)에서 '상세보기' 버튼을 누르면 영화상세화면(MovieDetailFragment) 으로 Fragment가 바뀌게 된다. 영화상세화면(MovieDetailFragment)으로 이미 화면이 전환된 상태에서, 다시 영화목록화면(MovieListFragment)으로 돌아가고싶은 경우, 자연스럽게 휴대폰의 뒤로가기 버튼을 누르게된다. 하지만 예상과는 다르게 다시 영화목록으로 돌아가는 대신 앱이 종료될 것이다.

 

두 개의 다른 액티비티가 실행된 것이 아니라, 단순히 MainActivity 내에서 화면만 교체된 상태이기 때문에 그저 MainActivity가 실행된 상태에서 뒤로가기 버튼을 눌러 앱을 끄는것과 다름없기때문에 일어나는 일이다.

(fragment의 이름은 설명의 편의를 위하여 임의의 이름을 사용한다..!)

 

이러한 경우, Fragment가 add() 혹은 replace() 될때마다, 별도의 stack에 계속해서 기록을 남겨두고 뒤로가기 버튼이 눌리면 현재 띄워져있는 Fragment를 종료하고 그 이전에 실행되어있던 Fragment가 다시 띄워지도록 하는 방법이 있다.

(정확한 설명인지는 모르겠다..! 대충 이렇게 이해해도 무리는 없을듯싶다ㅜㅜ)

 

처음 MainActivity가 onCreate() 실행될 때 MovieListFragment가 add() 될때부터 시작해서 계속해서 addToBackStack()를 실행하면 된다.

 

말이 너무 길다. 코드로 보자!

@Override
protected void onCreate(Bundle savedInstanceState) {

    ...

    android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    movieListFragment = new MovieListFragment();
    transaction.add(R.id.container, movieListFragment);
    transaction.addToBackStack(null); // 얘만 추가!
    transaction.commit();

	...
}

또, 새로운 프래그먼트로 replace() 할 때..!

transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, movieDetailFragment);
transaction.addToBackStack(null);
transaction.commit();

위와 같이 작성한다면, 영화상세화면에서 뒤로가기버튼을 눌렀을 때

정상적으로 다시 영화목록화면으로 돌아가게 된다!

(주의할점: 매 트랜잭션을 실행할 때마다 매번 새롭게 transaction=getSupportFragmentManager().beginTransaction(); 을 실행시켜 새롭게 초기화 시켜주어야한다. 안해도 되는줄알고 바로 replace() 실행했다가 에러가 났다)

 

 

 

 

 

4. 영화목록화면에서 한 화면에 여러 개의 포스터가 보이게 하는 방법! (★★)

- ViewGroup.setClipToPadding(false) 사용!!

 

나는 말을 참 어렵게하는 재주가 있다...4번째 tip의 이름을 정하기 힘들었다.

아래처럼 하는 방법을 말하는 것이다...

이거..!

PJT4를 진행하며 가장 애먹은 부분인듯 싶다.

구글링을 통해 스택오버플로우와 같은 사이트에서 여러 해법을 보아도 생각처럼 잘 되지 않았다.

 

하지만 몇번의 시행착오를 통하여 방법을 알아냈으니..!

ViewPager의 left와 right 부분이 일정한값의 padding을 갖도록하고,

ViewPager내의 page(각각의 fragment)는 그 절반만큼의 margin을 갖도록 하는 것이다.

 

pager = (ViewPager)(getContext().findViewById(R.id.moviePager));
pager.setOffscreenPageLimit(3);

// 여기서부터!
pager.setClipToPadding(false);

pager.setPadding(margin, 0, margin, 0); // int margin = [원하는 padding의 정도]
pager.setPageMargin(margin/2);

ViewPager가 속한 MovieListFragment에서 위와같은 코드를 추가하면 원하는 효과를 얻을 수 있다.

 

여기서, setClipToPadding() 이 핵심이다.

- 하위View를 가지고 있는 ViewGroup이면 어떤 View든 사용할 수 있는 메소드이다.(혹은 xml에서 android:clipToPadding 속성)

이는 부모View가 padding값을 가지고 있는 경우에도, 하위 View가 EdgeEffect를 가지는 경우에는 주어진 패딩값을 재조정(무시)할 수 있도록 해주는 것이다.

 

말이 매우어렵다. 해당 내용을 구글링해보아도 대부분 말로 설명을 해놓았는데 쉽게 설명하기 힘들어서 이해하기 힘들다.

그림을 활용하여 설명을 한 게시물이 있었는데, 해당 게시물 덕분에 비교적 쉽게 이해할 수 있었다.

(https://stackoverflow.com/questions/40953049/android-what-does-the-cliptopadding-attribute-do)

 

Android what does the clipToPadding Attribute do?

I would like to know what the clipToPadding attribute does for ViewGroup in Android ? I've been through the docs and some websites but none I have come across actually explain what it does and wha...

stackoverflow.com

이 메소드(혹은 attribute)를 잘 이해해두면 앞으로 유용하게 쓸일이 많을듯싶다. 한번볼때 확실히 봐두자.

 

 

 

 



 

 

이렇게 한 가지의 핵심포인트와, 프로젝트를 진행함에 있어서 도움이 될만한 4가지 추가 tip 

모두 정리해보았다!

 

최종 PJT4 완성 화면!!!

 

이번 프로젝트는 처음에 ViewPager의 개념을 이해하고 사용하는 것이 까다로울뿐,

이해하는 과정을 거치고 나면 프로젝트의 난이도 자체는 높지 않았던것 같다.

 

저번편에 마땅히 꿀팁이라고 작성할만한게 없어서 애좀 먹었는데,

이번 챕터에서는 팁으로 쓸만한 내용이 꽤 있어서 비교적 수월하게 작성한 것 같다ㅎㅎ

 

다음주에 진행하게 될 [PJT5 : 서버에서 영화정보 가져오기]는 개인적으로 가장 배우고싶었던 내용이다.

강의 열심히 듣고 프로젝트도 정성껏 수행하여 많은 꿀팁을 담은 4번째 게시물로 찾아뵙겠다.

(이것은 반말인가 존대인가...)

 

 

이만 끄읏

 

 

 

-  third_floor

+ Recent posts