일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 막내의막무가내 안드로이드 코틀린
- 부스트코스에이스
- 막내의막무가내 rxjava
- 막내의 막무가내
- 막내의막무가내 플러터 flutter
- flutter network call
- 프로그래머스 알고리즘
- 안드로이드 sunflower
- 막내의막무가내 안드로이드
- Fragment
- 안드로이드
- 막내의막무가내 안드로이드 에러 해결
- 주택가 잠실새내
- 막무가내
- 막내의막무가내 코틀린 안드로이드
- 막내의막무가내 코볼 COBOL
- 2022년 6월 일상
- 안드로이드 Sunflower 스터디
- 막내의막무가내 목표 및 회고
- 프래그먼트
- 막내의막무가내 SQL
- 막내의막무가내 플러터
- 막내의막무가내 프로그래밍
- 막내의막무가내
- 막내의 막무가내 알고리즘
- 주엽역 생활맥주
- 막내의막무가내 일상
- 막내의막무가내 알고리즘
- 막내의막무가내 코틀린
- 부스트코스
- Today
- Total
막내의 막무가내 프로그래밍 & 일상
[안드로이드] 안드로이드 CollapsingToolbarLayout UI 기록 본문
[2021-05-04 업데이트]
이전에 기본적인 CollapsingToolbarLayout 에 대해 구현해보고 알아보는 포스팅을 했었습니다.
여기에 문서를 보며 정리한 내용들이 있으니 먼저 참고해주시면 좋을 것 같습니다. ㅎㅎ
youngest-programming.tistory.com/353
이번에도 저번에 했던거와 비슷하지만 조금 더 응용해서 다음과 같은 영상의 UI를 구현해보고 이에 대해 기록하는 포스팅입니다.
사용한 프로젝트 링크는 다음과 같습니다.
리사이클러뷰와 스크롤뷰 CollapsingToolbarLayout 등을 섞어서 사용해 충돌이 좀 일어나서 이상하게 되고 이런식으로 구현하는건 처음이라 삽질을 좀 했었네요.(원하는 샘플도 못찾았고요 ㅠ 그래서 기록합니다 , youngest-programming.tistory.com/353 에 설명을 좀 달아놓긴 했습니다.)
CollapsingToolbarLayout 을 구현할 때 가장 이해하기 쉽게 설명하려면
CoordinatorLayout
-AppBarLayout
[AppBarLayout에 접히는 화면인 CollapsingToolbarLayout와 접히지 않을 Toolbar가 들어갈 것]
--CollapsingToolbarLayout
[접히는(스크롤에) 모션에 반응하여 나타나거나 사라질 레이아웃]
---Toolbar
[접히는(스크롤에) 모션에도 계속 남아 있을 툴바, 즉 CollapsingToolbarLayout 안에서 Toolbar안에 있는 것은 접혀도 뷰를 보존시킴]
-NestedScrollView
--ConstraintLayout [일반적인 레이아웃]
구조라고 보면 된다. 속성값은 매번 찾아가면서 필요한걸 사용하면 된다. ㅇㅇ 외울필요 XX
내가 구현한 디자인을 동영상으로 첨부해봤다.
https://tv.kakao.com/v/412543814
[UI]
[지역페이지 xml]
구현한 XML을 하나하나 뜯어봐서 분석해보도록 하겠습니다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="vm"
type="com.mtjin.nomoneytrip.views.localpage.LocalPageViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
android:theme="@style/toolbarTheme">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorWhiteFDFD"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_local"
android:layout_width="match_parent"
android:layout_height="@dimen/height_224dp"
android:scaleType="fitXY"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/img_product" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_local_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_marginStart="@dimen/margin_28dp"
android:layout_marginBottom="@dimen/margin_20dp"
android:textColor="@color/colorWhiteFDFD"
tools:text="지역명입니다." />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/height_80dp"
android:layout_gravity="top"
android:background="@android:color/transparent"
android:contentInsetStart="0dp"
android:contentInsetLeft="0dp"
android:contentInsetEnd="0dp"
android:contentInsetRight="0dp"
app:contentInsetEnd="0dp"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_16dp"
android:layout_marginTop="@dimen/margin_32dp"
android:onClick="@{()->vm.onBackClick()}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_back_title" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_local_toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorBlack2D2D"
android:textSize="@dimen/text_size_20sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/iv_back"
app:layout_constraintStart_toEndOf="@id/iv_back"
app:layout_constraintTop_toTopOf="@id/iv_back"
tools:text="지역명입니다" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_20dp"
android:onClick="@{()->vm.goLodgeSearch()}"
app:layout_constraintBottom_toBottomOf="@id/iv_back"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_back"
app:srcCompat="@drawable/ic_search_black" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fillViewport="true"
android:paddingBottom="@dimen/padding_36dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<TextView
android:id="@+id/tv_lodgment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_28dp"
android:layout_marginTop="@dimen/margin_28dp"
android:text="@string/nomoney_tour_local_text"
android:textColor="@color/colorBlack2D2D"
android:textSize="@dimen/text_size_18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_products"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_16dp"
android:clipToPadding="false"
android:nestedScrollingEnabled="false"
android:orientation="horizontal"
android:paddingStart="@dimen/margin_28dp"
android:paddingEnd="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_lodgment"
bind:setItems="@{vm.productList}"
tools:listitem="@layout/item_local_product" />
<TextView
android:id="@+id/tv_tour_introduce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_32dp"
android:text="@string/healing_tour_local_text"
android:textColor="@color/colorBlack2D2D"
android:textSize="@dimen/text_size_18sp"
app:layout_constraintStart_toStartOf="@id/tv_lodgment"
app:layout_constraintTop_toBottomOf="@id/rv_products" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_tours"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_18dp"
android:nestedScrollingEnabled="false"
android:orientation="horizontal"
android:paddingStart="@dimen/padding_28dp"
android:paddingEnd="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_tour_introduce"
bind:setItems="@{vm.tourIntroduceList}"
tools:listitem="@layout/item_tour_introduce" />
<TextView
android:id="@+id/tv_restaurant_introduce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_32dp"
android:text="@string/local_restaurant_text"
android:textColor="@color/colorBlack2D2D"
android:textSize="@dimen/text_size_18sp"
app:layout_constraintStart_toStartOf="@id/tv_lodgment"
app:layout_constraintTop_toBottomOf="@id/rv_tours" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_restaurants"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_16dp"
android:nestedScrollingEnabled="false"
android:orientation="horizontal"
android:paddingStart="@dimen/margin_28dp"
android:paddingEnd="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_restaurant_introduce"
bind:setItems="@{vm.restaurantIntroduceList}"
tools:listitem="@layout/item_tour_introduce" />
<TextView
android:id="@+id/tv_local_popular_tour"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_36dp"
android:text="@string/local_popular_review_text"
android:textColor="@color/colorBlack2D2D"
android:textSize="@dimen/text_size_18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="@id/tv_lodgment"
app:layout_constraintTop_toBottomOf="@id/rv_restaurants" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_reviews"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_22dp"
android:nestedScrollingEnabled="false"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/tv_local_popular_tour"
bind:setItems="@{vm.userReviewList}"
tools:itemCount="3"
tools:listitem="@layout/item_user_review" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_16dp"
android:layout_marginBottom="@dimen/margin_36dp"
android:onClick="@{()->vm.requestReviews()}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv_reviews"
app:srcCompat="@drawable/every_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
먼저 AppbarLayout에 대해 살펴보자
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
android:theme="@style/toolbarTheme">
별 특이점은 없다. android:fitsSystemWindows="true" 는 뷰가 차지할 수 있는 영역을 상태바 및 소프트키 영역을 제외한 영역까지 확장해주는 역할을 한다.
AppBarLayout 은 Theme 를 설정하여 툴바의 타이틀 색상 등을 바꿔줄 수 있는데 글자크기와 색상정도만 설정해줬습니다.
다음은 CollapsingToolbarLayout 이다.
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorWhiteFDFD"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
여기서는 app:contentScrim 은 특정 기준에 해당하는 만큼 레이아웃의 윗단까지 스크롤이 되면 이 특성이 활성화되어 CollapsingToolbarLayout 에 속성값(drawable)을 적용시켜줍니다.
app:layout_scrollFlags 는 NestedScrollView에서 스크롤 상태라고 CollapsingToolbarLayout 에 알려주고 이거에 반응하여 레이아웃이 나타나고 사라지게 됩니다.
저는 여기서 scroll|exitUntillCollapsed를 사용하였는데요!
scroll | enterAlwaysCollapsed 속성은 아래로 스크롤하는 동안 CollapsingToolbar가 확장되는 시간에 대해 lazy한 접근 방식을 사용합니다. 아래로 스크롤되는 순간, CollapsingToolbar는 NestedScrollView가 콘텐의 맨 위로 스크롤 된 후에만 확장됩니다. 즉 만약 엄청 긴 스크롤이 있고 맨아래까지 스크롤한 후 스크롤다운할 때 툴바위치(꼭대기겠죠) 까지 스크롤을 해야 그떄서야 툴바가 펴지기 시작한다는 뜻입니다.
다음 링크에서 정리했던게 있으니 참고하도록 합니다.
https://youngest-programming.tistory.com/353
ToolbarLayout 에 대해 보겠습니다.
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/height_80dp"
android:layout_gravity="top"
android:background="@android:color/transparent"
android:contentInsetStart="0dp"
android:contentInsetLeft="0dp"
android:contentInsetEnd="0dp"
android:contentInsetRight="0dp"
app:contentInsetEnd="0dp"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
큰 특이점은 없고 app:layout_collapseMode 에 대해서만 보면 될 것 같습니다. 이 속성값을 pin으로 할 경우, 스크롤을 할때 Toolbar가 최상단까지 위로 올라가면서 가장 최상단에 올라간 경우 고정 시켜주는 역할을 합니다.
마지막으로 AppbarLayout 밖의 계층인 NestedScrollView 쪽을 봐보겠습니다.
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fillViewport="true"
android:paddingBottom="@dimen/padding_36dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
app:layout_behavior="@string/appbar_scrolling_view_behavior" 속성을 설정함으로써 NestedScrollView의 반응에 따라 AppBarLayout이 반응됩니다.
가장 상위 레이아웃 계층인 CoordinatorLayout는 자식뷰의 스크롤의 변화 상태를 다른 자식뷰들에게 전달 해주는 역할을 합니다. 좀더 쉽게 말해 NestedScrollView나 RecyclerView 등에 스크롤의 상태를 판단하여 정의된 반응을 하기위한 View에 Behavior를 등록하면 됩니다.
저는 여기서 app:layout_behavior="@string/appbar_scrolling_view_behavior" 속성을 적용시켰고 CoordinatorLayout는 NestedScrollView가 스크롤시 layout_behavior에 정의된 레이아웃으로 스크롤 정보를 전달 하는 역할을 하고, 그럼 AppBarLayout의 ScrollingViewBehavior가 정보를 받아서 AppBarLayout 자신을 변형하도록 하는 구조입니다.
(참고 : https://blog.kmshack.kr/CoordinatorLayout%EA%B3%BC-Behavior%EC%9D%98-%EA%B4%80%EA%B3%84/)
ConstraintLaout에서 animateLayoutChanges 는 적용시켜줄 View의 부모 레이아웃에 넣어주면 알아서 animation 효과를 넣어줍니다다. 예를 들어, view를 감추고 보여줄때 자연스럽게 위아래로 스르륵한 효과를 넣고 싶을때 사용하면 유용합니다. ㅎㅎ
[지역페이지 Fragment]
CollapsingToolbarLayout 상태에 따라 뷰 변경
private fun initView() {
binding.appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
if (abs(verticalOffset) - appBarLayout.totalScrollRange == 0) { // 접혔을때
binding.tvLocalToolbarTitle.visibility = View.VISIBLE
} else {// 펴졌을때
binding.tvLocalToolbarTitle.visibility = View.GONE
}
})
}
[UI]
[홈 페이지 xml]
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="vm"
type="com.mtjin.nomoneytrip.views.home.HomeViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorWhiteFDFD"
app:expandedTitleTextAppearance="@android:color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_108dp"
android:paddingBottom="@dimen/padding_8dp"
app:layout_collapseMode="parallax">
<TextView
android:id="@+id/tv_where_go"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_28dp"
android:lineSpacingExtra="@dimen/line_spacing_extra_size_10sp"
android:text="@string/where_to_go_no_money_trip_question_text"
android:textColor="@color/colorBlack2D2D"
android:textSize="@dimen/text_size_22sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_26dp"
app:layout_constraintBottom_toBottomOf="@id/tv_where_go"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_where_go"
app:srcCompat="@drawable/img_main" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_28dp"
android:layout_marginTop="@dimen/margin_14dp"
android:layout_marginEnd="@dimen/margin_28dp"
android:background="@drawable/button_search"
android:drawableEnd="@drawable/ic_search_gray_24dp"
android:onClick="@{()->vm.goSearch()}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_where_go" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/height_80dp"
android:background="@android:color/transparent"
android:contentInsetStart="0dp"
android:contentInsetLeft="0dp"
android:contentInsetEnd="0dp"
android:contentInsetRight="0dp"
app:contentInsetEnd="0dp"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_app_logo2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_20dp"
android:layout_marginTop="@dimen/margin_28dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/logo" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_alarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_24dp"
android:onClick="@{()->vm.goAlarm()}"
android:src="@drawable/ic_alarm_off"
app:layout_constraintBottom_toBottomOf="@id/iv_app_logo2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_app_logo2" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_toolbar_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/margin_8dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/iv_alarm"
app:layout_constraintEnd_toStartOf="@id/iv_alarm"
app:layout_constraintTop_toTopOf="@id/iv_alarm"
app:srcCompat="@drawable/ic_search_black" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_hash_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_20dp"
android:orientation="horizontal"
android:paddingStart="@dimen/padding_28dp"
android:paddingEnd="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
bind:setItems="@{vm.hashTagList}"
tools:listitem="@layout/item_hash_tag" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<View
android:id="@+id/view_below_hashtag"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="@dimen/margin_12dp"
android:layout_marginBottom="@dimen/margin_12dp"
android:background="@color/colorWhiteGrayF4F4"
app:layout_constraintBottom_toTopOf="@id/rv_home_products"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_home_products"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@dimen/padding_28dp"
android:paddingTop="@dimen/padding_12dp"
android:paddingEnd="@dimen/padding_28dp"
android:paddingBottom="@dimen/padding_36dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/view_below_hashtag"
bind:setItems="@{vm.productList}"
tools:itemCount="2"
tools:listitem="@layout/item_product" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
[홈 페이지 Fragment]
private fun initView() {
viewModel.requestProducts()
binding.appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
if (abs(verticalOffset) - appBarLayout.totalScrollRange == 0) { // 접혔을때
binding.ivToolbarSearch.visibility = View.VISIBLE
} else {// 펴졌을때
binding.ivToolbarSearch.visibility = View.GONE
}
})
}
만약 영상과 천천히 CollapsingToolbarLayout 가 사라지는게 아닌 더 빨리 사라지게 하고 싶으면 다음과 같이 애니메이션 시간초를 설정해주면 됩니다.
app:scrimAnimationDuration="10" (ms)
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorWhiteFDFD"
app:expandedTitleTextAppearance="@android:color/transparent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:scrimAnimationDuration="10">
[P.S]
app:expandedTitleMarginStart
app:expandedTitleGravity
app:expandedTitleMarginBottom
app:expandedTitleTextAppearance
app:collapsedTitleTextAppearance
app:collapsedTitleGravity
등의 속성을 이용해서 툴바의 텍스트를 펼침, 접힘 상태의 모양을 구현해줄 수 있습니다.
Appearance에는 style로 모듈화해서 세팅하면됩니다. (Ex. testSize, testColor, fontFamily등)
그리고 뭐든 마찬가지지만 자주쓸 가능성이 있는 Collapsing Toolbar 는
AppBarLayout~CollapsingToolbarLayout~Toolbar로 모듈화해서
사용할 XML에 최상단 부모레이아웃을 CoordinatorLayout 로 한후 모듈화 한거를 <include> 해서 사용하면 좋습니다 :)
댓글과 공감은 큰 힘이 됩니다. 감사합니다 .!!!
[추가로 구현한 화면]
.
.
'안드로이드 > 코틀린 & 아키텍처 & Recent' 카테고리의 다른 글
[안드로이드] 하나의 바인딩어댑터에서 여러개의 리사이클러뷰 작업을 할 때 에러 처리 (0) | 2020.09.28 |
---|---|
[안드로이드] 안드로이드 상태바(StatusBar) 투명 처리 (2) | 2020.09.20 |
[안드로이드] WebView Sample 정리 및 프래그먼트에서 뒤로가기시 웹뷰 스택사용하기 (0) | 2020.09.12 |
[안드로이드] Android Material Calendar View 사용법 정리 (2) | 2020.09.09 |
[안드로이드] 안드로이드 BottomSheetDialog 샘플 (with top radius)(feat. 네 아니요 질문, Ratingbar 점수주기) (0) | 2020.09.08 |