안녕하세요. 블랙진입니다.
이번 시간에는 안드로이드에서 많이 사용하는 머티리얼 디자인 중 하나인 bottom sheets 에 대해서 알아보겠습니다.
구성
bottom sheets는 다음과 같은 3가지로 구성되어 있습니다.
1. Standard b ottom sheets
화면 하단에 보여주는 bottom sheets 입니다.
2. Modal b ottom sheets
다이얼로그 형태의 bottom sheets로 아래와 같이 화면 하단에 다이얼로그 형태로 보여줍니다.
3. Expanding bottom sheets
Standard bottom sheets 에서 더 나아가 일부 뷰를 미리 보여주며 스크롤을 통해 뷰를 확장할 수 있습니다.
구현
먼저 material 라이브러리를 build.gradle에 추가해 줍니다. material 최신 버전은 릴리즈 노트 를 확인해 주세요.
implementation 'com.google.android.material:material:1.2.0-alpha02'
Modal b ottom sheets
다이얼로그 bottom sheets는 일반 다이얼로그와 프래그먼트 다이얼로그 두가지 형태로 구현가능합니다.
1. 다이얼로그 구현
먼저 사용할 xml을 구현해줍니다. 저는 bottom_sheet.xml 이름으로 아래와 같이 xml을 구현했습니다.
bottom_sheet 접기
<? 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/bottomSheet" android :layout_width ="match_parent" android :layout_height ="wrap_content" android :background ="@android:color/holo_blue_bright" android :orientation ="vertical" android :padding ="12dp" > <LinearLayout android :layout_width ="match_parent" android :layout_height ="96dp" android :orientation ="horizontal" > <LinearLayout android :layout_width ="0dp" android :layout_height ="match_parent" android :layout_weight ="5" android :gravity ="center" android :orientation ="vertical" > <TextView android :layout_width ="wrap_content" android :layout_height ="wrap_content" android :text ="Welcome BlackJin Tistory" android :textColor ="#000000" android :textSize ="24sp" android :textStyle ="bold" /> </LinearLayout> </LinearLayout> <TextView android :layout_width ="wrap_content" android :layout_height ="wrap_content" android :layout_margin ="6dp" android :drawablePadding ="16dp" android :text ="Hello Android" /> <Button android :layout_width ="match_parent" android :layout_height ="wrap_content" android :layout_marginTop ="12dp" android :background ="@color/colorAccent" android :text ="Bottom Sheet" android :textColor ="@android:color/white" /> </LinearLayout>
접기
사용할 View에서 다이얼로그 구현 방법과 동일하게 작성해 줍니다.
val dialogView = layoutInflater .inflate(R.layout.bottom_sheet , null )val dialog = BottomSheetDialog(this ) dialog.setContentView(dialogView) dialog.show()
이게 전부입니다 :) BottomSheetDialog 를 만들어서 구현해 주시면 됩니다.
2. 프래그먼트 다이얼로그 구현
프래그먼트롤 생성할 시 Fragment Class를 만들어 줍니다.
class BottomSheetFragment : BottomSheetDialogFragment() { override fun onCreateView ( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.bottom_sheet , container, false ) } }
사용할 View 에서 아래와 같은 방법으로 구현해 줍니다.
val bottomSheetFragment = BottomSheetFragment() bottomSheetFragment.show(supportFragmentManager , bottomSheetFragment.tag )
E xpanding bottom sheets
다음은 확장 가능한 bottom sheets 구현법에 대해 보겠습니다.
acitivty_main.xml
<? xml version ="1.0" encoding ="utf-8" ?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns: android ="http://schemas.android.com/apk/res/android" android :layout_width ="match_parent" android :layout_height ="match_parent" > <Button android :id ="@+id/btnPersistent" android :layout_width ="wrap_content" android :layout_height ="wrap_content" android :layout_gravity ="center" /> <!-- Adding bottom sheet after main content --> <include layout ="@layout/bottom_sheet" /> </androidx.coordinatorlayout.widget.CoordinatorLayout> Expanding bottom sheets 기능은 한 화면에서 bottom sheet를 보여줘야 하므로 기존에 만든 bottom_sheet.xml을 include 해줍니다. 여기서 중요한 점은 bottom_sheet.xml을 CoordinatorLayout 안에 넣어주어야 합니다. 또한 다음 세가지 코드를 bottom_sheet.xml에 추가해 줍니다.
app :behavior_hideable ="false" bottom sheets를 화면에 안보일때 까지 내릴지 여부 입니다.
app :behavior_peekHeight ="100dp" 미리 보여지는 bottom sheets의 높이를 정합니다.
app :layout_behavior ="com.google.android.material.bottomsheet.BottomSheetBehavior" 위 behavior를 넣어 주어야만 정상적으로 동작합니다.
그럼 bottom_sheet.xml 을 최종적으로 아래와 같은 코드가 됩니다.
bottom_sheet 접기
<? 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/bottomSheet" android :layout_width ="match_parent" android :layout_height ="wrap_content" android :background ="@android:color/holo_blue_bright" android :orientation ="vertical" android :padding ="12dp" app :behavior_hideable ="false" app :behavior_peekHeight ="100dp" app :layout_behavior ="com.google.android.material.bottomsheet.BottomSheetBehavior" > <LinearLayout android :layout_width ="match_parent" android :layout_height ="96dp" android :orientation ="horizontal" > <LinearLayout android :layout_width ="0dp" android :layout_height ="match_parent" android :layout_weight ="5" android :gravity ="center" android :orientation ="vertical" > <TextView android :layout_width ="wrap_content" android :layout_height ="wrap_content" android :text ="Welcome BlackJin Tistory" android :textColor ="#000000" android :textSize ="24sp" android :textStyle ="bold" /> </LinearLayout> </LinearLayout> <TextView android :layout_width ="wrap_content" android :layout_height ="wrap_content" android :layout_margin ="6dp" android :drawablePadding ="16dp" android :text ="Hello Android" /> <Button android :layout_width ="match_parent" android :layout_height ="wrap_content" android :layout_marginTop ="12dp" android :background ="@color/colorAccent" android :text ="Bottom Sheet" android :textColor ="@android:color/white" /> </LinearLayout>
접기
MainAcitivty에 코드는 버튼을 눌렀을 때 bottom sheets를 컨트롤 할 수 있게 하는 기능으로 bottom sheets구현에 꼭 필요한 요소는 아닙니다. 버튼 기능을 구현하고 싶으신 분은 아래 코드를 봐주시면 됩니다.
MainActivity.class
MainActivity 접기
class MainActivity : AppCompatActivity() { override fun onCreate (savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main ) setBtnExpandSheet() val sheetBehavior = BottomSheetBehavior.from(bottomSheet) btnPersistent.setOnClickListener { if (sheetBehavior.state != BottomSheetBehavior.STATE_EXPANDED ) { sheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED setBtnCloseSheet() } else { sheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED setBtnExpandSheet() } } sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide (bottomSheet: View, slideOffset: Float) { // } override fun onStateChanged (bottomSheet: View, newState: Int) { when (newState) { BottomSheetBehavior.STATE_HIDDEN -> { } BottomSheetBehavior.STATE_EXPANDED -> { setBtnCloseSheet() } BottomSheetBehavior.STATE_HALF_EXPANDED -> { } BottomSheetBehavior.STATE_COLLAPSED -> { setBtnExpandSheet() } BottomSheetBehavior.STATE_DRAGGING -> { } BottomSheetBehavior.STATE_SETTLING -> { } } } }) } private fun setBtnExpandSheet () { btnPersistent.text = "Expand sheet" } private fun setBtnCloseSheet () { btnPersistent.text = "Close sheet" } }
접기
<참고 사이트>
Material Site