본문 바로가기
개발/안드로이드 개발

[안드로이드] CoordinatorLayout 활용 (Scrolling Techniques)

by 똘똘이박사 2016. 7. 22.

· 최초작성 : 2016. 07. 21.

최종수정 : 2016. 07. 21.

· 작성/수정내용 :

  - CoordinatorLayout 를 활용한 스크롤 이벤트




시작하기에 앞서


정말 너무 덥네요.

하고 싶은건 많고, 날은 너무 더워서 축축 늘어지고 있고...

모두 힘내세요!! 

 테스트 설정

 - Android Studio 2.1

   (2016.07.21 최신 업데이트)

 - min SDK :  API 19

 - 기본 템플릿 : Navigation Drawer Activity




# Scrolling Techniques 구현해 보기


안드로이드 Material Design 에서 가장 대표적인 사례는 지난 강좌에서 본 'Navigation Drawer Activity' 일 겁니다.

거기에 하나 더 해서 요거 하나 해보려고 합니다.






<출처 : material.google.com>




많이 보신 그림이죠?


스크롤링에 따라 상단(헤더) 부분이 나왔다가 사라졌다가 합니다.

애니메이션 처리가 되어 뭔가 멋있어 보입니다.


우리도 이거 만들어 보자구요~!


이 어플의 핵심은 지난 포스팅에서 이야기 했던

CoordinatorLayout 입니다.

그럼 이녀석 부터 찬찬히 살펴 보도록 하겠습니다.




CoordinatorLayout


참고 : https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html


CoordinatorLayout은 기본 API가 아닌 support design widget 입니다.

따라서 'Navigation Drawer Activity' 템플릿을 사용하지 않고 개발을 하려 한다면

반드시 'build.gradle' 파일에 아래와 같이 design을 support 하는 내용을 추가해 주어야 합니다.


dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
}

저희는 기본적인 것을 그냥 사용하니까 이미 위와 같이 추가가 되어 있습니다.


그럼 어떻게 그림을 그려야 하는지 구조부터 먼저 살펴 보도록 하겠습니다.

우선 왼쪽의 그림은 'Navigation Drawer Activity'의 기본적인 구조 입니다.

파일은 layout 안에 있는 app_bar_main.xml 파일입니다.





CoordinatorLayout 으로 전체적으로 감싸주고 있습니다.

그 안에 AppBarLayout와 본문 include 구문, 그리고 FloatingActionButton 이 있습니다.

AppbarLayout 안에는 Toolbar 이 있는 구조 입니다.



이 구조를 아래와 같이 변경을 해야 합니다.





CoordinatorLayout 가 전체를 감싸는 것은 변함이 없고

새롭게 RecyclerView가 추가 되었으며,

AppBarLayout 안에도 CollapsingToolbarLayout 를 사용해

ImageView와 Toolbar 을 감싸고 있습니다.


그럼 새로 추가된 녀석들을 살펴 볼께요



RecyclerView


RecyclerView 는 Android 5.0 버전 발표와 함께 Support-Library-V7에 정식추가가 되어 지원되기

시작한 View 입니다. 이전에는 ListView를 사용하여 왔는데, ListView가 커스텀하기에 어렵고,

구조적으로 성능상 문제가 있어, 이를 대체 할 수 있게 되었습니다.


RecyclerView는 기본적으로 LayoutManager를 사용하여 Item 을 관리하고

LayoutManager를 통해 효과적으로 item을 정렬하고 애니메이션등을 다룰 수 있습니다.


주요 클래스로는

 Adapter

 기존의 ListView에서 사용하는 Adapter와 같은 개념으로 data와 item에 대한 view를 생성 

 ViewHolder

 재활용 View에 대한 모든 서브 view를 보유

 LayoutManager

 item의 항목을 배치

 ItemDecoration

 item 항목에서 서브 view에 대한 처리

 ItemAnimation

 item 항목이 추가, 제거 되거나 정렬 될 때 애니메이션 처리


점점 알아야 할것도 많고, 뭔가 복잡해 지는데요

당행스럽게도 아쉽게 이번에 구현해 볼 내용에서는

위의 클래스를 구현하지 않아도 충분히 만들 수 있습니다.

(위의 내용은 나중에 CardView를 하게 되면 그때 다뤄 보도록 하겠습니다.)



CollapsingToolbarLayout


CollapsingToolbarLayout는 FrameLayout을 상복받은 Layout로 

Toolbar를 애니메이션을 통해 확장해 주는 용도로 사용하고 있습니다.


우선 기본적인 본문이 들어갈 content_main.xml 파일의 구조는 아래 그림과 같습니다.



위와 같은 상태로는 본문의 내용이 너무 짧기 때문에

스크롤이 발생되지 않습니다.

따라서 스크롤이 발생 할 수 있도록 TextView를 몇개 더 추가해 주고

layout_height 값을 많이 줘서 스크롤이 발생할 수 있을 만큼 본문이 길어지게 해주야 합니다.


전 layout_height 값을 100dp로 설정하고 TextView를 5개 더 추가하여 본문 길이늘 늘려 놓았습니다.

<TextView
android:id="@+id/textView02"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_below="@id/textView01"
android:text="Hello World 02 !" />

요런 식으로요ㅎㅎㅎ


하지만 이렇게 한다고 스크롤이 생기지 않습니다.

스크롤이 생기게 하려면 ScollView를 사용하여 전체를 한 번 감싸주면 되는데요

ScollView로는 우리가 하려는 스크롤링 이벤트를 처리 할 수 없기 때문에 다른 녀석을 써줘야 합니다.

바로 NestedScrollView 를 사용합니다.


그럼 본분의 구조가 아래처럼 바뀌게 됩니다.





이렇게 하면 일단 스크롤은 되겠지만 아직 우리가 원하는

Toolbar가 작아지면서 색상이 변하는 애니메이션이 제대로 동작하지 않습니다.


그럼 이제 이런것들이 가능해 지도록 작업해 봅시다.



우선 다시 app_bar_main.xml 로 돌아와서

CollapsingToolbarLayout 에 layout_scrollFlags 속성을 사용하여 스크롤시 헤더에 대한 적절한 flag를 설정해 

다음과 같은 종류가 있습니다.


 scroll

 스크롤 이벤트에 반응할 모든 view에 반드시 이 플래그를 설정해야 합니다. 그렇지 않으면 화면상단에 고정되어 있게 됩니다.

 enterAlways

 아래ㅉ족 방향으로 스크롤 할때마다 이 보기가 표시됩니다. ('quitk return')

 exitUntilCollapsed

 해당뷰에 minHeight를 정의하고 있으면, Toolbar가 해당 크기 까지만 축소가 됩니다.

 (가장 많이 사용됩니다.)

 enterAlwaysCollapsed

 해당뷰에 minHeight속성의 크기로 시작해 맨위로 스크롤이 될때만 전체 높이로 확장하게 됩니다.


<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">



그 다음으로 살펴봐야 하는 속성, layout_collapseMode 속성이 있습니다.

이 속성은 Toolbar 안에 설정하며, 스크롤이 발생 시 Toolbar의 최종 형태가 어떤 형태인지를 결정해 줍니다.

이미지를 사용했다면 ImageView에도 속성을 넣어 줘야 합니다.


 pin

 CollapsingToolbarLayout이 완전히 축소되면 툴바는 화면위에 고정됩니다. 

 parallax 

 툴바가 축소되는 동안Parallax모드로 동작하도록 합니다. 옵션으로 layout_collapseParallaxMultipler 속성을 사용하면 transition의 translation Multiplier를 설정할 수 있습니다. 

(예 : app:layout_collapseParallaxMultiplier="0.7") 그리고 CollapsingToolbarLayout에 app:contentScrim 속성을 사용하여 최소화 되었을때 툴바의 색상을 변경 할 수 있습니다.


<ImageView
android:id="@+id/imageView01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
android:src="@drawable/bar_img_png"
app:layout_collapseMode="parallax" />

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />

이렇게 하면 스크롤이 발생하여 본문의 내용을 위로 올리면 image 가 작아지면서 사라지고 툴바는 상단에 고정이 되게 됩니다.



자 이제 마지막으로 가장 중요한 속성이 하나 남았습니다.

지난 포스팅에서 이야기 했던 layout_behavior 입니다. 이 속성이 지정되어 있지 않다면

아무리 스크롤링을 해도 이벤트가 발생하지 않습니다.

이 속성은 RecyclerView가 CoordinatorLayout 과 함께 동작하기 위해서 반드시 필요 합니다. 즉 레이아웃이 RecyclerView의 스크롤 이벤트에 반응할 수 있게 해줍니다.


app_bar_main.xml 과 content_main.xml 코드 전체를 한 번 살펴보고 마칩니다.


< app_bar_main.xml >

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
android:fitsSystemWindows="true"
tools:context="com.example.freehoon.material02.MainActivity">

<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="250dp"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">

<ImageView
android:id="@+id/imageView01"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
android:src="@drawable/bar_img_png"
app:layout_collapseMode="parallax" />

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />

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

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

<include layout="@layout/content_main" />

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />

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

< content_main.xml >

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_height="match_parent"
android:layout_width="match_parent">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"

tools:context="com.example.freehoon.material02.MainActivity"
tools:showIn="@layout/app_bar_main">

<TextView
android:id="@+id/textView01"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="Hello World 01 !" />

<TextView
android:id="@+id/textView02"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_below="@id/textView01"
android:text="Hello World 02 !" />

<!-- TextView03 ~ TextView05는 생략 -->

<TextView
android:id="@+id/textView06"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_below="@id/textView05"
android:text="Hello World 06 !" />

</RelativeLayout>
</android.support.v4.widget.NestedScrollView>

반응형