ラベル BottomSheetDialogFragment の投稿を表示しています。 すべての投稿を表示
ラベル BottomSheetDialogFragment の投稿を表示しています。 すべての投稿を表示

2025年4月12日土曜日

Android BottomSheetDialogFragmentの実装方法を解説

どうも。どっことです。今回はBottomSheetDialogFragmentについて解説します。

BottomSheetDialogFragmentについて解説

BottomSheetDialogFragmentは通常のダイアログから派生したクラスで、下からスライドインで生えてくるような見え方が印象的です。最初に表示するダイアログの高さや、スクロールの制御もでき、通常のダイアログよりカスタマイズ性が高い点も特徴的です。

実装

最小構成で実装する場合は以下の手順です。

  1. BottomSheetDialogFragment用のstyleを追加する。
  2. 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)を変更して下さい。このときBottomSheetDialogThemenavigationBarColorを同じ色になるように注意してください。

最初に表示される高さを調整したい

いくつか注意が必要です。

まず、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に対してpeekHeightstateを設定することで、最初に表示されるダイアログの高さを調整することができます。

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より実装が必要なポイントが多いですが、見せ方のカスタマイズできる点や元の画面表示の邪魔をしない点では、ユーザに優しい表示方法の一つと言えます。使い所を意識して使いこなせるようになりたいですね。

参考

移行予定

どうも。どっことです。 タイトルの通りですが、諸事情により GitHubPage に移行予定です。 https://mkt120.github.io/ この備忘録に記載の内容を転記しつつ、今後はこちらのページを更新していく予定です。