Android/Android UI

안드로이드 - BottomSheet , BottomSheetBehavior

최데브 2021. 8. 31. 10:19

간혹 앱을 사용하다보면 위아래로 슬라이드 하면서 크기가 늘어났다가 줄어들었다가 하는 화면을 찾아 볼 수 있다. 

 

출처 : https://material.io/components/sheets-bottom#anatomy

이런 화면들 말이다. 

밑의 레이아웃을 위로 당기면 높이가 늘어나고 내려도 다 사라지지는 않고 남아있는 형태의 sheet.

 

이런걸 만들고 싶었는데 어떻게 하면 좋을지 고민하다가 한번 만들어봤다.

 

언제나 그렇듯 코드로 알아보자.

 

        <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <include layout="@layout/bottom_sheet" />
        </androidx.coordinatorlayout.widget.CoordinatorLayout>

CoordinatorLayout 이라는게 눈에 띈다. 

CoordinatorLayout 은 

  • FrameLayout 같이 좌표를 자유롭게 지정 가능하다.
  • 한개의 parent 아래 포함된 여러개의 child view 를 behavior 라는 것을 이용해서 다양한 애니메이션 효과를 표현해 낼 수 있다.

라고 간단하게 설명가능하다 . 

나처럼 바텀시트에 사용할 수도 있고 , 밑으로 스크롤 했을때 앱바가 들어나는 효과들도 CoordinatorLayout  을 이용해서 만들곤 한다.

 

behavior  를 사용해서 만들어야하기 때문에  bottom_sheet 라는 것을 CoordinatorLayout  으로 감싸줘야한다.

공식문서에도 CoordinatorLayout  의 자식뷰로 있어야한다고 적혀있는것을 확인 할 수 있다. 

(처음에 이걸 몰라서 계속 오류가 났다. 뭐든 기본을 확실하게 알자.)

 

그럼 이번에는 bottom_sheet.layout 파일을 살펴보자.

 

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:background="#fff"
    android:orientation="vertical"
    android:padding="10dp"
    app:behavior_hideable="false"
    app:behavior_peekHeight="120dp"
    app:layout_behavior="@string/bottom_sheet_behavior">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginHorizontal="26dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="@+id/store_detail_mapView">

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="19dp"
            android:includeFontPadding="false"
            android:text="안녕하세요"
            android:textColor="@color/black_color"
            android:textSize="20dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"></TextView>

        <TextView
            android:id="@+id/textView5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="반갑습니다."
            android:textColor="@color/grey_text"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView4"></TextView>


        <TextView
            android:id="@+id/textView6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="반가워요"
            android:textColor="@color/black_color"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView5"
            app:layout_constraintVertical_bias="0.166"></TextView>

        <TextView
            android:id="@+id/textView7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="반갑군요"
            android:textColor="@color/black_color"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView6"
            app:layout_constraintVertical_bias="0.1"></TextView>

        <TextView
            android:id="@+id/textView8"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="정말로 반갑습니다."
            android:textColor="@color/black_color"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView7"
            app:layout_constraintVertical_bias="0.1"></TextView>

        <TextView
            android:id="@+id/a_tv"
            android:layout_width="150dp"
            android:layout_height="50dp"
            android:layout_marginStart="16dp"
            android:background="@color/button_blue"
            android:gravity="center"
            android:text="버튼1"
            android:textColor="@color/black_color"
            android:textSize="18dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView8"
            app:layout_constraintVertical_bias="0.505"></TextView>

        <TextView
            android:id="@+id/b_tv"
            android:layout_width="150dp"
            android:layout_height="50dp"
            android:background="@color/button_blue"
            android:gravity="center"
            android:text="버튼2"
            android:textColor="@color/black_color"
            android:textSize="18dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/a_tv"
            app:layout_constraintTop_toBottomOf="@+id/textView8"
            app:layout_constraintVertical_bias="0.505"></TextView>
    </androidx.constraintlayout.widget.ConstraintLayout>

</LinearLayout>

생각보다 별거없다. 일반 activity layout 을 만드는거랑 비슷하다.

알아둬야할건

최상위 LinearLayout 에서

   app:behavior_hideable="false"
    app:behavior_peekHeight="120dp"
    app:layout_behavior="@string/bottom_sheet_behavior"

위 3개다.  첫번째는    app:behavior_hideable="false" 바텀시트가 화면에서 완전히 숨겨지는지 아닌지를 체크한다. 

false 라면 내가 의도한대로 화면에 아래에 계속 조금이라도 남아있다.

pp:behavior_peekHeight="120dp" 는 최소로 남아있을때 높이를 설정하는 속성이다. 

 

마지막으로 액티비티에서 어떻게 사용하는지 보자.

 

        var sheetBehavior = BottomSheetBehavior.from(view.bottom_sheet)
        sheetBehavior.setBottomSheetCallback(object  : BottomSheetBehavior.BottomSheetCallback(){
            override fun onStateChanged(bottomSheet: View, newState: Int) {
                when (newState) {
                    BottomSheetBehavior.STATE_HIDDEN -> {
                    }
                    BottomSheetBehavior.STATE_EXPANDED -> {
                    }
                    BottomSheetBehavior.STATE_COLLAPSED -> {
                    }
                    BottomSheetBehavior.STATE_DRAGGING -> {
                    }
                    BottomSheetBehavior.STATE_SETTLING -> {
                    }
                }
            }

            override fun onSlide(bottomSheet: View, slideOffset: Float) {
            }

        })

나는 fragment 에서 만들었기 때문에 위 코드를 onCreateView 안에다가 넣어줬는데 

액티비티에서 사용할거라면 onCreate 안에다가 넣으면 될것이다.

 

안에 state 에 따라서 어떻게 보여줄지 설정할수도 있는것 같지만 나는 사용하지는 않았다. 

 

쓸 일이 있는 사람에게 도움이 됐으면 좋겠다. 

반응형