29

BottomSheetDialogFragmentを拡張するフラグメントの状態を、Androidサポートデザインライブラリ(v23.2.1)を使用してBottomSheetBehavior#setState(STATE_EXPANDED)を使用して展開するにはどうすればよいですか?BottomSheetDialogFragmentを展開する状態を設定する

https://code.google.com/p/android/issues/detail?id=202396は言う:

ボトムシートが最初にSTATE_COLLAPSEDに設定されています。展開する場合は、BottomSheetBehavior#setState(STATE_EXPANDED)を呼び出します。ビューのレイアウトの前にメソッドを呼び出すことはできません。

suggested practiceは、最初に膨張するためのビューが必要ですが、私は私がフラグメント(BottomSheetDialogFragment)にBottomSheetBehaviourを設定しますかどうかはわかりません。

View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet); 
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); 

答えて

70

"ビューレイアウトの前にメソッドを呼び出すことはできません。" < ---これは手掛かりです。

ダイアログには、と表示された後に起動されるリスナーがあります。と表示されます。ダイアログがレイアウトされていない場合は、ダイアログを表示できません。

だから、あなたのモーダルボトムシート(BottomSheetFragment)のonCreateDialog()で、ちょうど(ダイアログへの参照を持っていたら、どこかまたは)ダイアログを返す前に、呼び出し:

// This listener's onShow is fired when the dialog is shown 
dialog.setOnShowListener(new DialogInterface.OnShowListener() { 
    @Override 
    public void onShow(DialogInterface dialog) { 

     // In a previous life I used this method to get handles to the positive and negative buttons 
     // of a dialog in order to change their Typeface. Good ol' days. 

     BottomSheetDialog d = (BottomSheetDialog) dialog; 

     // This is gotten directly from the source of BottomSheetDialog 
     // in the wrapInBottomSheet() method 
     FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); 

     // Right here! 
     BottomSheetBehavior.from(bottomSheet) 
      .setState(BottomSheetBehavior.STATE_EXPANDED); 
    } 
}); 

をで私の私のカスタムBottomSheetは次のようになりました。

@SuppressWarnings("ConstantConditions") 
public class ShareBottomSheetFragment extends AppCompatDialogFragment { 

    @NonNull @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 

     BottomSheetDialog dialog = 
       new BottomSheetDialog(getActivity(), R.style.Haute_Dialog_ShareImage); 

     dialog.setContentView(R.layout.dialog_share_image); 

     dialog.findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       dismiss(); 
      } 
     }); 

     dialog.setOnShowListener(new DialogInterface.OnShowListener() { 
      @Override 
      public void onShow(DialogInterface dialog) { 
       BottomSheetDialog d = (BottomSheetDialog) dialog; 

       FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); 
       BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); 
      } 
     }); 

     SwitchCompat switchview = (SwitchCompat) dialog.findViewById(R.id.switchview); 
     switchview.setTypeface(FontCache.get(dialog.getContext(), lookup(muli, NORMAL))); 

     // 

     return dialog; 
    } 
} 

これが役立つかどうか教えてください。

public class SimpleInitiallyExpandedBottomSheetFragment extends BottomSheetDialogFragment { 

    @NonNull @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 

     BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState); 

     dialog.setOnShowListener(new DialogInterface.OnShowListener() { 
      @Override 
      public void onShow(DialogInterface dialog) { 
       BottomSheetDialog d = (BottomSheetDialog) dialog; 

       FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); 
       BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); 
      } 
     }); 

     // Do something with your dialog like setContentView() or whatever 
     return dialog; 
    } 
} 

が、私は本当に誰もがベースとしてBottomSheetFragmentが返す以外の何かをdoesntのことをしたいと思う理由を参照していけない:あなたもようBottomSheetDialogFragmentを上書きすることができます

UPDATE

注意BottomSheetDialog

+0

ありがとう、私はこの方法を試しました。'BottomSheetDialogFragment'をjanky(オープニングアニメーションのフレームをスキップしているように見える)にします。 編集:Android MarshmallowとKitKatのデバイスでこれをテストしました – user2560886

+1

これは私にとっては完璧に機能します。スキップしない。ダイアログを返す以外に何かしていますか?私は良いアイデアを持つことができるようにあなたのコードであなたのポストを更新する場合は感謝します。 – efemoney

+0

私はジャンクに気づいていない。うまく動作します。 – rpattabi

8

あなたが使いたい場合は、onfreviewView() onCreateDialog()と一緒に行くとは対照的に、は、あなたのBottomSheetを作成するには、ここにあなたがあなたのonCreateView()法の下で追加する必要がありますコードは次のとおりです。

@Nullable 
@Override 
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
    getDialog().setOnShowListener(new DialogInterface.OnShowListener() { 
     @Override 
     public void onShow(DialogInterface dialog) { 
      BottomSheetDialog d = (BottomSheetDialog) dialog; 
      View bottomSheetInternal = d.findViewById(android.support.design.R.id.design_bottom_sheet); 
      BottomSheetBehavior.from(bottomSheetInternal).setState(BottomSheetBehavior.STATE_EXPANDED); 
     } 
    }); 
    return inflater.inflate(R.layout.your_bottomsheet_content_layout, container, false); 
} 
+1

また、getDialogをまったく呼び出す必要はありません。私はそれを行う最もクリーンな方法は、onCreateViewとonCreateDialogの両方をオーバーライドすることです。 onCreateViewでビューを構築し(任意のフラグメントと同様に)、onCreateDialogでダイアログ固有のコードを実行します(インスタンスを取得するためにsuper.onCreateDialogを呼び出します)。 – Stimsoni

+0

これは私の一日を保存します。ありがとう。 – AndroidRuntimeException

1
dialog.setOnShowListener(new DialogInterface.OnShowListener() { 
      @Override 
      public void onShow(DialogInterface dialog) { 
       BottomSheetDialog d = (BottomSheetDialog) dialog; 

       FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet); 
       BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); 
      } 
     }); 

私はNullPointExceptionに会いましたd.findViewById(android.support.design.R.id.design_bottom_sheet)がnullを返すため、BottomSheetBehavior.from(bottomSheet)

これは変です。 Android MonitorのWatchesにDEBUGモードのこのコード行を追加し、通常、Framelayoutを返すことがわかりました。

はここBottomSheetDialogでwrapInBottomSheetのコードです:時々

private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) { 
     final CoordinatorLayout coordinator = (CoordinatorLayout) View.inflate(getContext(), 
       R.layout.design_bottom_sheet_dialog, null); 
     if (layoutResId != 0 && view == null) { 
      view = getLayoutInflater().inflate(layoutResId, coordinator, false); 
     } 
     FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet); 
     BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback); 
     if (params == null) { 
      bottomSheet.addView(view); 
     } else { 
      bottomSheet.addView(view, params); 
     } 
     // We treat the CoordinatorLayout as outside the dialog though it is technically inside 
     if (shouldWindowCloseOnTouchOutside()) { 
      coordinator.findViewById(R.id.touch_outside).setOnClickListener(
        new View.OnClickListener() { 
         @Override 
         public void onClick(View view) { 
          if (isShowing()) { 
           cancel(); 
          } 
         } 
        }); 
     } 
     return coordinator; 
    } 

、私はR.id.design_bottom_sheetandroid.support.design.R.id.design_bottom_sheetと等しくないことがわかりました。それらは異なるR.javaで異なる値を持ちます。

android.support.design.R.id.design_bottom_sheetR.id.design_bottom_sheetに変更しました。

dialog.setOnShowListener(new DialogInterface.OnShowListener() { 
      @Override 
      public void onShow(DialogInterface dialog) { 
       BottomSheetDialog d = (BottomSheetDialog) dialog; 

       FrameLayout bottomSheet = (FrameLayout) d.findViewById(R.id.design_bottom_sheet); // use R.java of current project 
       BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED); 
      } 
     }); 

これ以上NullPointExceptionはありません。

0

ソフトキーボードが表示されているときに、onShow()を使用したすべての結果がランダムなレンダリングの不具合を引き起こします。以下のスクリーンショットを参照してください。 - BottomSheetダイアログは、画面の下部にありませんが、キーボードが表示されたように配置されています。この問題は、常に発生するわけではなく、かなり頻繁に発生します。プライベートメンバの反射と

enter image description here

UPDATE

私の解決策は不要です。ソフトキーボードを隠した後にダイアログを表示して表示するためにpostDelayed(約100ms)を使用する方が良い解決法です。 onShow()で上記の解決策がOKです。

Utils.hideSoftKeyboard(this); 
mView.postDelayed(new Runnable() { 
    @Override 
    public void run() { 
     MyBottomSheetDialog dialog = new MyBottomSheetDialog(); 
     dialog.setListener(MyActivity.this); 
     dialog.show(getSupportFragmentManager(), TAG_BOTTOM_SHEET_DLG); 
    } 
}, 100); 

だから私は他のソリューションを実装するが、BottomSheetDialogがプライベートとしてすべてのメンバーを持っているので、それは、リフレクションを使用する必要があります。しかし、それはレンダリングのバグを解決します。 BottomSheetDialogFragmentクラスは、BottomSheetDialogを作成するonCreateDialogメソッドを持つAppCompatDialogFragmentのみです。自分のクラスを作成するAppCompatDialogFragmentの独自の子を作成し、BottomSheetDialogを拡張し、プライベート動作メンバーへのアクセスを解決し、onStartメソッドでSTATE_EXPANDED状態に設定します。

public class ExpandedBottomSheetDialog extends BottomSheetDialog { 

    protected BottomSheetBehavior<FrameLayout> mBehavior; 

    public ExpandedBottomSheetDialog(@NonNull Context context, @StyleRes int theme) { 
     super(context, theme); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     try { 
      Field privateField = BottomSheetDialog.class.getDeclaredField("mBehavior"); 
      privateField.setAccessible(true); 
      mBehavior = (BottomSheetBehavior<FrameLayout>) privateField.get(this); 
     } catch (NoSuchFieldException e) { 
      // do nothing 
     } catch (IllegalAccessException e) { 
      // do nothing 
     } 
    } 

    @Override 
    protected void onStart() { 
     super.onStart(); 
     if (mBehavior != null) { 
      mBehavior.setSkipCollapsed(true); 
      mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); 
     } 
    } 
} 


public class AddAttachmentBottomSheetDialog extends AppCompatDialogFragment { 

    .... 

    @NonNull 
    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     return new ExpandedBottomSheetDialog(getContext(), getTheme()); 
    } 

    .... 
} 
0

OnResumeでBottomsheetDialogFragment状態が

@Override 
    public void onResume() { 
     super.onResume(); 
     if(mBehavior!=null) 
      mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); 
    } 

この問題を解決します適用onShow(DialogInterfaceダイアログ)とpostDelayedはアニメーショングリッチ

0

を引き起こす可能性があり、私はこれを処理するBottomSheetDialogFragmentのサブクラスを書いた:

public class NonCollapsableBottomSheetDialogFragment extends BottomSheetDialogFragment { 

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState); 

    bottomSheetDialog.setOnShowListener(new DialogInterface.OnShowListener() { 
     @Override 
     public void onShow(DialogInterface dialog) { 
      FrameLayout bottomSheet = bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet); 

      BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); 
      behavior.setSkipCollapsed(true); 
      behavior.setState(BottomSheetBehavior.STATE_EXPANDED); 
     } 
    }); 
    return bottomSheetDialog; 
} 

}

BottomSheetDialogFragmentの代わりにこのクラスを拡張して、独自のボトムシートを作成します。

0

私が実装する最も簡単な方法は、ここでは、android.support.design.R.id.design_bottom_sheetを見つけ、を拡大してボトムシートの状態を設定されている、以下の通りです。

は、表示の高さが画面の高さの0.5を超える場合は常にCOLLAPSED状態に固定されていたため、手動でスクロールしてフルボトムシートを表示する必要がありました。

class BottomSheetDialogExpanded(context: Context) : BottomSheetDialog(context) { 

    private lateinit var mBehavior: BottomSheetBehavior<FrameLayout> 

    override fun setContentView(view: View) { 
     super.setContentView(view) 
     val bottomSheet = window.decorView.findViewById<View>(android.support.design.R.id.design_bottom_sheet) as FrameLayout 
     mBehavior = BottomSheetBehavior.from(bottomSheet) 
     mBehavior.state = BottomSheetBehavior.STATE_EXPANDED 
    } 

    override fun onStart() { 
     super.onStart() 
     mBehavior.state = BottomSheetBehavior.STATE_EXPANDED 
    } 
} 
関連する問題