[Android] Coordinatorlayout 배워보기 #1 - AppbarLayout



Coordinatorlayout 배워보기 #1


요약

  • FrameLayout 같이 좌표를 자유롭게 지정 가능하다.
  • android sdk 24.1.0(Nougat)에 포함되었다.
  • 만약 compile sdk 가 24.1.0 이전 버전이라면 
  • 한개의 parent 아래 포함된 여러개의 child view 를 behavior 라는 것을 이용해서 다양한 애니메이션 효과를 표현해 낼 수 있다.


순서

  • AppbarLayout 구성하기
  • CoordinateLayout Behavior
  • Custom Behavior


1. AppbarLayout


새 프로젝트를 생성한다. Empty Activity 로 생성하고 api level 은 19로 한다. (하지만 처음부터 api level을 24로 해도 된다)




프로젝트를 생성했으면 activity_main.xml 파일을 수정하도록 한다.

단, api level 24 이상에서는 support:design library 가 포함되어 있어서 바로 CoordinatorLayout 을 추가해도 되지만 그 이하에서는 gradle 파일에 아래 dependency 를 추가해 준다.




apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.jirancomms.kr.coordinatorlayoutexam1"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    // 자동추가 되는 depedencies
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    // 새로 추가 할 dependencies
    compile 'com.android.support:support-annotations:27.1.1'
    compile 'com.android.support:design:26.1.0'
}
build.gradle



gradle sync 를 마친 후 activity_coordinator.xml 파일을 열어서 싹 지운 후 아래 코드를 붙여넣기 한다. (context 부분만 자신의 package 명에 맞게 변경해 주면 된다)


<?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"
    tools:context="com.jirancomms.kr.coordinatorlayoutexam1.MainActivity">

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


이 상태에서 빌드 후 앱을 실행 시켜 본다. Hello World! 가 보인다면 성공한 것이다. 여기에 하나씩 추가를 해보면서 익혀보도록 하자.




CoordinatorLayout 은 frameLayout 처럼 parent view 역할을 한다. 이제 이 안에 적절한 view 들을 넣어줄 차례인데, 가장 일반적으로 많이 쓰이는 Appbar 를 한번 추가해 보도록 하자. 
참고로 Appbar 는 api level 11 부터 지원하는 Actionbar 와 api level 21 부터 지원하는 Toolbar 를 포괄적으로 부르는 용어이다.

AppBarLayout 내에 Toolbar 를 추가 하고 앱을 실행시켜 보도록 한다.


<?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"
    tools:context="com.jirancomms.kr.coordinatorlayoutexam1.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <android.support.v7.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:title="Test Appbar">

        </android.support.v7.widget.Toolbar>
    </android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>




Toolbar 를 추가한 실행화면



허? 근데 뭔가 Appbar 가 두개가 생겨 버렸다

이유는 프로젝트를 api level 19 로 생성 하다 보니 Toolbar가 아닌 Actionbar 가 기본으로 보여졌기 때문이다. 
지금은 Actionbar 대신 Toolbar 를 사용할 예정이니 Actionbar 는 안보이도록 styles.xml을 수정하도록 한다.


<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>
styles.xml

DarkActionBar 를 NoActionBar 로 변경 후 다시 앱을 실행시켜 보면 기존의 Actionbar 는 사라져 있는 것을 볼 수 있다.


Actionbar 가 사라졌다



이제 고정되어 있는 Toolbar 를 Scroll 에 따라서 커지기도 하고 작아지기도 하는 효과를 만들어 보기 위해 AppBarLayout 의 height 을 300dp 정도로 수정해 주도록 한다.


<?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="300dp"
    tools:context="com.jirancomms.kr.coordinatorlayoutexam1.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <android.support.v7.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:title="Test Appbar">

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

        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Toolbar 를 CollapsingToolbarLayout 으로 감싼다.




수정후 다시 실행해서 AppBarLayout 영역을 스크롤링 해보면 아래처럼 ToolBar 영역의 title이 자동으로 줄어들었다 커졌다 하는 것을 볼 수 있다. 
참고로 파란색으로 된 부분이 AppBarLayout 영역이다.





뭔가 별로 해준게 없는데 저런 효과가 나는게 왠지 불안하다. 
꼭 뭔가 외워서 써야만 할 것 같고.. 결론만 말하자면 외워야 하는 부분도 있고 이해해야 하는 부분도 있다.

이제 스크롤링 시 Toolbar 를 보여지게 하거나 감추는 flag 를 적용해보자.
그 설정은 app:layout_scrollFlags 에 따라서 결정이 된다. 
이것을 테스트 해보기 위해 Toolbar 아래에 recyclerView 를 하나 추가해서 테스트 해보도록 하자.



activity_main.xml 에 아래와 같이 NestedScrollView 를 복사해서 붙여넣어 준다.



<?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"
    tools:context="com.jirancomms.kr.coordinatorlayoutexam1.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        >

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|enterAlways"
            android:minHeight="200dp">

            <android.support.v7.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionbarSize"
                app:title="Test Appbar">

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

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

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/main.scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:fillViewport="true"
        android:scrollbars="none"
        android:descendantFocusability="blocksDescendants"
        >

        <android.support.v7.widget.RecyclerView
            android:id="@+id/main.scrollview.recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
activity_main.xml




그리고 MainActivity.java 파일에 아래 코드를 복사해서 붙여넣기 해준다.





public class MainActivity extends AppCompatActivity {

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

        final List<String> testStrings = new ArrayList<>();
        for(int i = 0; i < 100; i++) {
            testStrings.add(i + " 번째 item");
        }
        RecyclerView recyclerView = findViewById(R.id.main_scrollview_recyclerview);
        recyclerView.setAdapter(new RecyclerView.Adapter<TestViewHolder>() {
            @Override
            public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View view = View.inflate(getApplicationContext(), android.R.layout.simple_list_item_1, null);
                return new TestViewHolder(view);
            }

            @Override
            public void onBindViewHolder(TestViewHolder holder, int position) {
                holder.textView.setText(testStrings.get(position));
            }
            public int getItemCount() {
                return testStrings.size();
            }
        });
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }

    public static class TestViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;
        public TestViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(android.R.id.text1);
        }

        @Override
        public String toString() {
            return super.toString();
        }
    }
}
MainActivity.java



실행해 보면 100개의 아이템이 아래에 추가 되어 있는 것을 볼 수 있고, 이를 스크롤 하면 위에 AppbarLayout 이 동작하는 것을 볼 수 있다.

이제 layout_scrollFlags 설정을 하나씩 실행해 가면서 차이점을 살펴 보도록 하자.



scroll | enterAlways

scroll | enterAlways



enterAlways는 스크롤을 아래로 이동 시 AppbarLayout 이 완전히 사라졌다가 스크롤을 위쪽으로 이동하게 되면 AppbarLayer 전체가 보여진다. 이 flag 는 스크롤 이동 시 바로 메뉴같은게 보여지고 싶을 때 사용하면 유용하다. 예를 들어 웹브라우저 같은 경우 스크롤을 아래로 내릴 땐 주소창이 감춰지다가 살짝 위로 스크롤을 하게 되면 주소창이 보여지는 경우를 생각해 보면 된다.





scroll | enterAlwaysCollapsed


enterAlwaysCollapsed는 스크롤을 아래로 이동 시  AppbarLayout 이 완전히 사라졌다가 스크롤을 위쪽으로 이동하게 되면 Toolbar 가 minHeight 만큼만 내려오고 스크롤이 최 상단에 도착 시 나머지 Appbar의 전체가 내려오게 된다.

고로, 이 flag 는 Toolbar 의 minHeight 에 영향을 받는다. 따라서 Toolbar size 를 조금 변경 시켜놓고 테스트를 해야한다. 아래처럼 Toolbar 의 height 와 minHeight 를 변경해 놓고 실행해 보자.


            <android.support.v7.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="150dp"
                android:minHeight="100dp"
                app:title="Test Appbar">


응? 근데 실행시켜 보면 알겠지만 enterAlways 때와 별 차이가 없어 보인다. 그 이유는 이 flag는 enterAlways 와 조합을 해서 사용해야 되는 것이기 때문이다.



scroll | enterAlways  | enterAlwaysCollapsed


이 조합으로 수정하여 다시 앱을 실행시켜 보자.


scroll | enterAlways  | enterAlwaysCollapsed

스크롤을 아래로 내리면 AppbarLayout 이 완전히 사라졌다가 반대 방향으로 스크롤을 올리게 되면 딱 Toolbar의 minHeight 만큼만 보여지게 되고 스크롤 최 상단에 도착 시 모든 Appbar 영역이 나타나게 된다.

enterAlwaysCollapsed 를 사용할 때는 반드시 enterAlways 와 조합해서 사용해야 한다는 점을 명심하자.


scroll | exitUntilCollapsed



exitUntilCollapsed


exitUntilCollapsed는 스크롤을 아래, 위로 이동 시 Toolbar 의 minHeight 만큼만 보여지고 스크롤이 최 상단에 도착 시 나머지 Appbar의 전체가 내려오게 된다. 위의 enterAlways  | enterAlwaysCollapsed 을 조합했을 때와 다른 점은 위쪽으로 스크롤링 해도 AppbarLayout 이 완전히 사라지지 않는 다는 것이다.



scroll | snap



scroll | snap


snap 은 마치 자석에 달라붙는 것 같은 느낌으로 AppbarLayout size 의 절반 크기를 기준으로 아래 위로 달라 붙는 flag 이다. 



이 다섯개의 flag 는 적절히 조합을 해서 사용해야 완전한 기능을 사용할 수 있다. 

각 flag 의 역할을 정확히 알고 적절한 곳에 사용하도록 하자. 

댓글

댓글 쓰기

이 블로그의 인기 게시물

[Android] Android 3.2 업데이트 후 끊김현상 해결 방법

[Google Cloud Platform] 클라우드 플랫폼 생성하기