2017/07/10

Replace Dialog to BottomSheet

従来はコンテンツを他アプリへ共有する際などにダイアログUIが使われていましたが,
昨今では, マテリアルデザインのModal bottom sheetsで説明されているように, ボトムシートUIにするのが一般的です.

ボトムシートを実装するにはいくつか方法がありますが, 既存のダイアログをボトムシートに変更したいだけであれば, AppCompatDialogを継承したBottomSheetDialogFragment/BottomSheetDialogを使うだけで比較的容易に対応できます.

// 継承元をDialogFragmentからBottomSheetDialogFragmentに変更
// public class MyDialogFragment extends DialogFragment
public class MyDialogFragment extends BottomSheetDialogFragment {

...

  @Override public Dialog onCreateDialog(Bundle savedInstanceState) {
    ...
    View view = binding.getRoot();
    MyBottomSheetDialog bottomSheet = new MyBottomSheetDialog(getContext());
    bottomSheet.setContentView(view);

    // ボトムシートダイアログを返却する
    return bottomSheet;
  }
}

ボトムシートの幅はスクリーンサイズに合わせて最大幅を調節することが推奨されています.

Screen width Minimum distance from screen edge (in increments) Minimum sheet width (in increments)
960dp 1 increment 6 increments
1280dp 2 increments 8 increments
1440dp 3 increments 9 increments

BottomSheetDialogの横幅を決めるためには, ダイアログの場合と同じくウィンドウの幅を調整する必要があります.
ウィンドウの幅はBottomSheetDialogのコンストラクタで指定することができます.

private static class ShareBottomSheetDialog extends BottomSheetDialog {
  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 横画面などでボトムシートが間延びしないように最大幅を設ける
    Optional.ofNullable(getWindow())
      .ifPresent(window -> window.setLayout(
        Math.min(displayWidth, maxWidth), 
        ViewGroup.LayoutParams.MATCH_PARENT);    

また, ボトムシート自体をどこまで引き出した状態で表示するかをpeekHeightを使って指定できます. peekHeightBottomSheetBehaviorで指定することができます.

bottomSheet.setContentView(view);

// 横画面などでもシェアアイコンが表示されるようにダイアログの高さ(peek)を確保する
BottomSheetBehavior behavior 
  = BottomSheetBehavior.from((View) view.getParent());
behavior.setPeekHeight(height);

以上です.