이번에 사용하게 된 Bottom Sheet에 대해 간단한 내용을 정리한다.

Bottom Sheet

  • Android Material Design 중 하나이다.
  • 크게 3가지의 종류가 존재한다.
  1. standard bottom sheet
    • 화면 하단에 보여주는 bottom sheet
  2. modal bottom sheet
    • 다이얼로그 형태의 bottom sheet으로 화면 하단에 다이얼로그 형태로 보여준다.
  3. expading bottom sheet
    • standard bottom sheet에서 더 나아가 일부 뷰를 미리 보여주며 스크롤을 통해 뷰를 확장할 수 있다.

[Dependency]

  • 먼저, material 의존성을 추가한다.
1
2
3
4
ext {
materialVersion = '1.3.0-alpha01'
}
implementation “com.google.android.material:material:$materialVersion”

[Implementation]

  • Bottom Sheet의 역할을 할 레이아웃을 작성한다.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<?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">

<data>

<variable
name="vm"
type="app.woovictory.presentation.vm.FilterViewModel" />
</data>


<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:clipToPadding="false"
android:padding="@dimen/padding_16"
app:layout_behavior="@string/bottom_sheet_behavior">

<TextView
android:id="@+id/titleFilter"
style="@style/Text.FilterTitleStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:text="@string/title_filter"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<TextView
android:id="@+id/titleAges"
style="@style/Text.DescriptionStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_16"
android:text="@string/title_ages"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/titleFilter" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ageList"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_8"
app:layoutManager="com.google.android.flexbox.FlexboxLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/titleAges" />

<TextView
android:id="@+id/titleStyles"
style="@style/Text.DescriptionStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_16"
android:text="@string/title_styles"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ageList" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/styleList"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_8"
app:layoutManager="com.google.android.flexbox.FlexboxLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/titleStyles" />

<View
android:id="@+id/divider"
android:layout_width="0dp"
android:layout_height="0.1dp"
android:layout_marginTop="@dimen/margin_16"
android:background="@color/colorGray"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/styleList" />

<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_8"
android:layout_marginBottom="@dimen/margin_8"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider">

<TextView
android:id="@+id/resetButton"
style="@style/Text.FilterTextStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="2"
android:drawableStart="@drawable/img_undo"
android:drawablePadding="@dimen/margin_8"
android:gravity="center_vertical"
android:onClick="@{() -> vm.onClickReset()}"
android:text="@string/action_undo" />

<Button
style="@style/Text.ButtonTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="3"
android:background="@drawable/bg_complete_button"
android:gravity="center"
android:onClick="@{() -> vm.onClickComplete()}"
android:text="@string/action_complete"
android:textColor="@color/colorWhite" />

</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
  • BottomSheedDialogFragment를 상속받아 Fragment를 만들고, 레이아웃을 연결한다.
1
2
3
4
5
6
7
8
9
10
class FilterFragment : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.filter_bottom_sheet, container, false)
return binding.root
}
}
  • Activity에서 이벤트를 통해 Bottom Sheet을 보여주도록 코드를 작성하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ShopActivity : BaseActivity<ActivityShopBinding>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_filter -> {
FilterFragment.newInstance().apply { show(supportFragmentManager, this.tag) }
true
}
else -> super.onOptionsItemSelected(item)
}
}
}

Reference