どうも。どっことです。今回はBottomSheetDialogFragment
について解説します。
BottomSheetDialogFragmentについて解説
BottomSheetDialogFragment
は通常のダイアログから派生したクラスで、下からスライドインで生えてくるような見え方が印象的です。最初に表示するダイアログの高さや、スクロールの制御もでき、通常のダイアログよりカスタマイズ性が高い点も特徴的です。
実装
最小構成で実装する場合は以下の手順です。
-
BottomSheetDialogFragment
用のstyle
を追加する。 -
BottomSheetDialogFragment
のサブクラスを実装する。
順番に解説していきます。
styleを追加する
<style name="BottomSheetDialogTheme" parent="@style/Theme.Design.Light.BottomSheetDialog"/>
BottomSheetDialogThemeというstyleを追加します。
サブクラスを実装する
BottomSheetDialogFragment
を継承したCustomBottomSheetDialogFragment
クラスを追加します。
class CustomBottomSheetDialogFragment :
BottomSheetDialogFragment(R.layout.fragment_bottom_sheet_dialog) {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return BottomSheetDialog(requireContext(), R.style.BottomSheetDialogTheme)
}
}
ダイアログ内で表示するためのコンテンツもレイアウトファイル(fragment_bottom_sheet_dialog.xml
)として追加しておきましょう。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:gravity="center"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="hello_world!!"/>
</FrameLayout>
これだけ実装すれば、BottomSheetDialogFragmentを表示することができます。
class MainActivity : AppCompatActivity() {
...
fun showDialog() {
val dialog = CustomBottomSheetDialogFragment()
dialog.show(supportFragmentManager, null)
}
}
実際に表示すると、以下のようになります。
その他
ナビゲーションバーの表示を格好良くしたい
styleをカスタマイズします。
<style name="BottomSheetDialogTheme" parent="@style/Theme.Design.Light.BottomSheetDialog">
<item name="android:windowIsFloating">false</item>
</style>
windowIsFloating:false
を設定することで、以下のようにナビゲーションバーの表示が不透明になり比較的自然な表示になります。
さらにダイアログとナビゲーションバーの表示を同じにしたい場合は、以下のようにBottomSheet
というスタイルを追加し、BottomSheetDialogTheme
のスタイルに追加してください。
<style name="BottomSheet" parent="@style/Widget.Design.BottomSheet.Modal">
<item name="android:background">@android:color/darker_gray</item>
</style>
<style name="BottomSheetDialogTheme" parent="@style/Theme.Design.Light.BottomSheetDialog">
<item name="android:windowIsFloating">false</item>
<item name="android:navigationBarColor">@android:color/darker_gray</item>
<item name="bottomSheetStyle">@style/BottomSheet</item>
</style>
ダイアログの背景色を指定したい場合は BottomSheet
スタイルの
背景色(background
)を変更して下さい。このときBottomSheetDialogTheme
のnavigationBarColor
を同じ色になるように注意してください。
最初に表示される高さを調整したい
いくつか注意が必要です。
まず、BottomSheetDialogFragmentの呼び出し元のレイアウトがCoordinatorLayout
である必要があります。これは、高さ調整をするためのBottomSheetBehavior
クラスの制約となります。
ここではActivityがダイアログを表示するサンプルなので、Activityのレイアウトを調整します。
<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/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ダイアログを表示"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
次に、ダイアログが表示されるタイミングでBottomSheetBehaviorを生成しますが、この時に渡すViewをcom.google.android.material.R.id.design_bottom_sheet
でfindViewByIdで参照する必要があります。これもBottomSheetBehaviorクラスの制約です。
class CustomBottomSheetDialogFragment :
BottomSheetDialogFragment(R.layout.fragment_bottom_sheet_dialog) {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return BottomSheetDialog(requireContext(), R.style.BottomSheetDialogTheme)
.also { dialog ->
dialog.setOnShowListener {
dialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
?.let {
BottomSheetBehavior.from(it).also {
// 後述
}
}
}
}
}
}
Viewを参照するIDがSDK側のものなので、正直あまりいい実装とは言えないという所感です。より適切な実装がみつかりましたら、この記事を更新しようと思います。
ここまでを調整した上で、生成するBottomSheetBehaviorに対してpeekHeight
やstate
を設定することで、最初に表示されるダイアログの高さを調整することができます。
class CustomBottomSheetDialogFragment :
BottomSheetDialogFragment(R.layout.fragment_bottom_sheet_dialog) {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return BottomSheetDialog(requireContext(), R.style.BottomSheetDialogTheme)
.also { dialog ->
dialog.setOnShowListener {
dialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
?.let {
BottomSheetBehavior.from(it).also {
it.peekHeight =
resources.getDimensionPixelSize(R.dimen.bottom_sheet_dialog_initial_height)
it.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
}
}
}
peekHeight
には最初に表示する高さを、state
にはBottomSheetBehavior.STATE_COLLAPSED
を指定してください。
まとめ
今回はBottomSheetDialogFragment
について解説しました。通常のDialogFragmentより実装が必要なポイントが多いですが、見せ方のカスタマイズできる点や元の画面表示の邪魔をしない点では、ユーザに優しい表示方法の一つと言えます。使い所を意識して使いこなせるようになりたいですね。