Установить состояние BottomSheetDialogFragment в развернутое
как вы устанавливаете состояние расширения фрагмента BottomSheetDialogFragment
для расширения с помощью BottomSheetBehavior#setState(STATE_EXPANDED)
использование библиотеки дизайна поддержки Android (v23.2.1)?
https://code.google.com/p/android/issues/detail?id=202396 говорит:
нижние листы сначала устанавливаются в STATE_COLLAPSED. Вызовите BottomSheetBehavior#setState (STATE_EXPANDED), если вы хотите развернуть его. Обратите внимание, что вы не можете вызвать метод перед макетами представления.
в рекомендуется требует, чтобы сначала был завышен вид, но я не уверен, как я установлю BottomSheetBehaviour на фрагмент (BottomSheetDialogFragment
).
View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
7 ответов
"обратите внимание, что вы не можете вызвать метод перед макетами представления."
приведенный выше текст является ключом.
диалоги имеют прослушиватель, который запускается после того, как диалог показали. Диалог не может быть показан, если он не выложен.
так, в onCreateDialog()
вашего модального нижнего листа (BottomSheetFragment
), непосредственно перед возвращением диалога (или в любом месте, как только у вас есть ссылка на диалог), звоните:
// 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;
}
}
Дайте мне знать, если это помогает.
обновление
обратите внимание, что вы также можете переопределить BottomSheetDialogFragment
as:
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
не делает ничего, кроме как вернуть BottomSheetDialog
.
ответ efeturi велик, однако, если вы хотите использовать onCreateView() чтобы создать свой BottomSheet, а не идти с onCreateDialog(), вот код, который вам нужно будет добавить в свой 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);
}
Я написал подкласс 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
создать свой собственный нижний лист.
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 в BottomSheetBehavior.from(bottomSheet)
, потому что d.findViewById(android.support.design.R.id.design_bottom_sheet)
возвращает значение null.
это странно. Я добавляю эту строку кода в часы на мониторе Android в режиме отладки и обнаружил, что она возвращает Framelayout нормально.
вотwrapInBottomSheet
в BottomSheetDialog:
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_sheet
не равно android.support.design.R.id.design_bottom_sheet
. Они имеют различное значение в различном R.java - ...
изменение android.support.design.R.id.design_bottom_sheet
to R.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.
применить bottomsheetdialogfragment состояние в OnResume решит эту проблему
@Override
public void onResume() {
super.onResume();
if(mBehavior!=null)
mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
onShow (DialogInterface dialog) и postDelayed может вызвать сбой анимации
все результаты с использованием onShow () вызывают случайную ошибку рендеринга при отображении мягкой клавиатуры. См. скриншот ниже-диалоговое окно BottomSheet не находится внизу экрана, но помещается так, как отображалась клавиатура. Эта проблема возникает не всегда, но довольно часто.
обновление
мое решение с отражением частного члена не нужно. С помощью postDelayed (около 100 мс) для создания и отображения после hide soft keyboard это лучшее решение. Тогда вышеуказанные решения с onShow () в порядке.
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-это только AppCompatDialogFragment с методом onCreateDialog, который создает BottomSheetDialog. Я создаю собственный дочерний элемент 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());
}
....
}
самый простой способ, который я реализовал, как показано ниже, Здесь мы находим android.поддержка.дизайн.R.id.design_bottom_sheet и установка Нижнего состояния листа как расширенный.
без этого, мой нижний лист всегда застревал в разрушенном состоянии Если высота просмотра больше 0,5 высоты экрана, и я должен вручную прокрутить, чтобы просмотреть полный нижний лист.
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
}
}