[안드로이드] CoordinatorLayout and Bottom sheet

hee09·2021년 11월 2일
2

안드로이드

목록 보기
16/20
post-thumbnail

참조
안드로이드 developer - CoordinatorLayout
틀린 부분을 댓글로 남겨주시면 수정하겠습니다..!!

CoordinatorLayout

CoordinatorLayout은 FrameLayout을 상속 받아 작성되었습니다.

CoordinatorLayout는 다음과 같은 경우에 주로 사용합니다.
1. 화면의 최상위를 꾸미거나 크롬 레이아웃으로 사용할 때
2. 하나 혹은 그 이상의 자식 View들과 상호작용 하기 위한 container로 사용

간단히 이야기하자면 뷰 간의 상호 작용을 목적으로 만든 레이아웃 입니다. 대표적으로 사용하는 예가 화면에 함께 보이는 여러 뷰 가운데 하나의 뷰가 드래그 될 때 다른 뷰가 함께 드래그되는 경우입니다. 모든 뷰의 상호작용을 지원하지 않고, 주로 FloatingActionButton과 Snackbar의 상호 연동, AppBar와 RecyclerView의 상호 연동 부분에 이용됩니다.

AppBar와 RecyclerView의 상호 작용은 AppBar 파트에서 다루고, 이곳에서는 FloatingActionButton과 Snackbar의 상호작용을 알아보겠습니다.


1. depedency 설정

Coordinatorlayout은 app 또는 module 수준의 build.gradle 파일에 depedency를 추가합니다.

dependencies {
    implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
}

2. 간단한 예시

FloatingActionButton을 화면의 오른쪽 아래에 배치하고 Snackbar를 띄우면 Snackbar에 의해 FloatingActionButton이 가려집니다. 이럴 경우 CoordinatorLayout을 사용하여 FloatingActionButton과 Snackbar를 서로 상호작용 시켜주면 가려지지 않습니다.

CoordinatorLayout 적용 전CoordinatorLayout 적용 후
First ImageSecond Image

XML에서는 CoordinatorLayout 태그 안에 FloatingActionButton을 넣고, Snackbar를 만드는 코드에서 첫 번째 매개변수가 Snackbar가 만들어지는 위치인데 그 곳을 CoordinatorLayout으로 지정하면 됩니다.

  • xml
<androidx.coordinatorlayout.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:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Coordinator">

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floating"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/ic_floating"
        app:fabSize="normal"
        app:layout_anchorGravity="bottom|right|end"
        app:rippleColor="#FFFFFF"
        android:layout_gravity="bottom|end"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
  • activity 코드
// CoordinatorLayout 초기화
val coordinatorLayout = findViewById<CoordinatorLayout>(R.id.root_layout)

// FloatingActionButton 초기화
val floating = findViewById<FloatingActionButton>(R.id.floating)
// Button 리스너
floating.setOnClickListener {
    // Snackbar를 생성하는데 매개변수로 Snackbar가 만들어지는 위치, 메세지, 시간
    Snackbar.make(coordinatorLayout, "Snack bar message!!", Snackbar.LENGTH_LONG)
        // 추가 Action 설정
        .setAction("Action Message!!") {
            // Action 클릭했을 시 코드
        }.show() // Snackbar show
}

이와 같이 CoordinatorLayout은 View간의 상호작용을 하는데 많이 사용됩니다.


3. Bottom Sheet

CoordinatorLayout과 함께 유용하게 사용하는 Bottom Sheet가 있습니다.

Bottom Sheet는 액티비티 창의 콘텐츠 영역 구성과 별도로 하단에 부가 내용을 보여주기 위해 사용됩니다.

Bottom Sheet는 persistent bottom sheetmodal bottom sheet 두 가지 형태가 있으며, 작성 방법도 다르고 화면에 보이는 형태도 다릅니다.

persistent bottom sheetmodal bottom sheet
First ImageSecond Image

3.1 persistent bottom sheet

persistent bottom sheet는 액티비티 출력시 초기부터 화면에 출력할 수 있으며, 사용자가 스크롤 하여 확대 및 축소를 할 수 있습니다. 또한, persistent bottom sheet가 화면에 보여도 뷰 개념이므로 메인 콘텐츠 부분을 사용자가 얼마든지 이용할 수 있습니다.

XML 작성

XML 파일에 Persistent bottom sheet를 위한 뷰를 추가합니다.

<!-- Bottom Sheet를 이용하기 위해 CoordinatorLayout을 선언 -->
<androidx.coordinatorlayout.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:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- Activity Main Content -->
    <Button />

    <!-- Persistent Bottom Sheet -->
    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:background="#ebebeb"
        android:orientation="vertical"
        android:padding="16dp"
        app:behavior_hideable="true"
        app:behavior_peekHeight="120dp"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <!-- persistent bottom sheet의 Content -->
        <TextView />

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Botton Sheet를 이용하기 위해 CoordinatorLayout을 루트 태그로 설정합니다.

그리고 그 아래 Activity의 메인 콘텐츠를 표현하기 위한 뷰와 Bottom Sheet를 위한 뷰를 추가합니다.

여기서 LinearLayout안에 있는 app:layout_behavior 속성이 중요한데 속성값을 com.google.android.material.bottomsheet.BottomSheetBehavior로 설정하면 BottomSheetBehavior 클래스가 특별하게 처리하여 bottom sheet로 동작합니다.

참조 - BottomSheetBehavior은 CoordinatorLayout의 하위 뷰를 bottom sheet로 만들기 위한 상호 작용 동작 플러그인입니다.

나머지 설정된 속성은 다음과 같습니다.

  • layout_height : bottom sheet의 최대 스크롤 크기
  • behavior_peekHeight : bottom sheet의 초기 크기
  • behavior_hideable : 사용자 스크롤에 의해 사라질 것인지를 설정

액티비티 코드

이제 XML에 등록된 persistent bottom sheet를 위한 뷰를 획득하고, BottomSheetBehavior.from() 함수를 이용하면 persistent bottom sheet가 됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
	// persistent bottom sheet로 사용할 view 획득
        // coordinatorLayout안에 설정되어 있으므로 그곳에서 findViewById를 사용하여 얻어온다
        val bottomSheet = coordinatorLayout.findViewById<View>(R.id.bottom_sheet)
        // 위에서 획득한 view를 BottomSheet로 지정
        val persistenetBottomSheet: BottomSheetBehavior<View> = 
            BottomSheetBehavior.from(bottomSheet)
}

사용자에 의해 bottom sheet가 이벤트가 발생하면 처리도 가능합니다.

BottomSheetBehavior의 nested 클래스인 BottomSheetCallback 추상 클래스를 구현하면 되는데, onStateChanged()는 bottom sheet의 상태값이 변경될 때 호출되고, onSlide()는 bottom sheet가 스크롤될 때 호출됩니다.

val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
    // bottom sheet의 상태값 변경
    override fun onStateChanged(bottomSheet: View, newState: Int) {

    }

    // botton sheet가 스크롤될 때 호출
    override fun onSlide(bottomSheet: View, slideOffset: Float) {
        
    }
}

onStateChanged() 함수로 bottom sheet의 상태값이 전달되는데, 상태값으로는 다음과 같은 값이 존재합니다.

  • STATE_COLLAPSED : bottom sheet가 붕괴된 상태
  • STATE_DRAGGINH : bottom sheet가 드래그중인 상태
  • STATE_EXPANDED : bottom sheet가 확장된 상태
  • STATE_HALF_EXPANDED : bottom sheet가 반만 확장된 상태
  • STATE_HIDDEN : bottom sheet가 사라진 상태
  • STATE_SETTLING : bottom sheet가 안착된 상태

3.2 modal bottom sheet

modal bottom sheet는 다이얼로그 개념입니다. 액티비티에서 특정 상황이 되었을 때 코드에서 AlertDialog와 같이 show() 함수를 이용해 출력해야합니다. modal bottom sheet가 뜨면 액티비티 원래의 창은 회색으로 처리되고(정지 상태), 사용자 이벤트가 발생하지 않습니다. 결국, modal bottom sheet는 액티비티에서 다이얼로그나 메뉴 부분을 Bottom Sheet 형태로 하단에 보여주기 위해 사용됩니다.

다이얼로그와 마찬가지이므로 modal bottom sheet를 위한 XML 파일을 별도로 설정합니다.
modal bottom sheet안에서 보여줄 레이아웃을 작성하면 됩니다.

XML 작성(예시에서는 RecyclerView를 이용하기 위해 RecyclerView만 작성)

<!-- Modal bottom sheet를 위한 레이아웃 -->
<!-- Recyclerview를 사용하기 위해 RecyclerView 선언 -->
<androidx.recyclerview.widget.RecyclerView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="16dp" />

액티비티 코드

// modal bottom sheet를 위한 xml 파일 초기화
val view = layoutInflater.inflate(R.layout.lab4_modal_sheet, null)
// modal bottom sheet 객체 생성
modalBottomSheet = BottomSheetDialog(this)
// layout 파일 설정
modalBottomSheet?.setContentView(view)
// 다이얼로그 보여주기
modalBottomSheet?.show()

우선 XML 파일을 inflate합니다. 그 후 BottomSheetDialog가 modal bottom sheet를 지원하는 클래스이므로 BottomSheetDialog의 setContentView() 함수에 inflate한 뷰를 지정하고, show() 함수로 화면에 띄우면 됩니다.(AlertDialog에서 custom layout을 지정하는 것과 비슷합니다)


CoordinatorLayout과 Bottom sheet 예제 소스 코드

profile
되새기기 위해 기록

0개의 댓글