How do you set the state of a fragment extending BottomSheetDialogFragment
to expanded using BottomSheetBehavior#setState(STATE_EXPANDED)
using the
All results with using onShow() cause random render bug when soft keyboard is displayed. See screenshot bellow - BottomSheet dialog is not at bottom of screen but is placed like keyboard was displayed. This problem is not occurs always but quite often.
UPDATE
My solution with reflection of private member is unnecessary. Using postDelayed (with about 100 ms) for creating and showing dialog after hide soft keyboard is better solution. Then the above solutions with onShow() are 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);
So I implement other solution, but it requires using reflection, because BottomSheetDialog has all members as private. But it solves render bug. BottomSheetDialogFragment class is only AppCompatDialogFragment with onCreateDialog method which create BottomSheetDialog. I create own child of AppCompatDialogFragment which create my class extends BottomSheetDialog and which solves access to private behavior member and set it in onStart method to STATE_EXPANDED state.
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());
}
....
}
A simplistic and elegant solution:
BottomSheetDialogFragment
could be subclassed to address this:
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(com.google.android.material.R.id.design_bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setSkipCollapsed(true);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});
return bottomSheetDialog;
}
}
So extend this class instead of BottomSheetDialogFragment
to create your own bottom sheet.
Note
Change com.google.android.material.R.id.design_bottom_sheet
to android.support.design.R.id.design_bottom_sheet
if your project uses old Android support libraries.