„Pamiętaj, że nie możesz wywołać metody przed wyświetlaniem układów”.
Powyższy tekst jest wskazówką.
Dialogi mają słuchacza, który jest zwolniony kiedy zostanie okno dialogowe pokazane . Nie można wyświetlić okna dialogowego, jeśli nie jest ustawione.
Tak więc w onCreateDialog()
twoim modalnym arkuszu dolnym ( BottomSheetFragment
), tuż przed zwróceniem okna dialogowego (lub gdziekolwiek, gdy masz odniesienie do okna dialogowego), wywołaj:
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);
}
});
W moim przypadku mój zwyczaj BottomSheet
okazał się:
@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;
}
}
Daj mi znać, jeśli to pomoże.
AKTUALIZACJA
Pamiętaj, że możesz również zastąpić BottomSheetDialogFragment
jako:
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);
}
});
return dialog;
}
}
Ale naprawdę nie rozumiem, dlaczego ktokolwiek miałby chcieć to zrobić, ponieważ baza BottomSheetFragment
nie robi nic poza zwracaniem pliku BottomSheetDialog
.
AKTUALIZACJA DLA ANDROIDX
Podczas korzystania z AndroidX zasób znaleziony wcześniej pod adresem android.support.design.R.id.design_bottom_sheet
można teraz znaleźć pod adresem com.google.android.material.R.id.design_bottom_sheet
.
BottomSheetDialogFragment
wygląda to dziwnie (wydaje się, że pomija klatki w animacji początkowej) podczas przechodzenia od zwiniętego do rozwiniętego zachowania. Edycja: przetestowano to na urządzeniach z Androidem Marshmallow i KitKatandroid.support.design.R
po aktualizacji bibliotek wsparcia?android.support.design.R
, tak jak @natario. Używamimplementation "com.google.android.material:material:1.0.0"
. W projekcie używam również AndroidX.com.google.android.material.R.id.design_bottom_sheet
Odpowiedź efeturi jest świetna, jednak jeśli chcesz użyć onCreateView () do utworzenia arkusza BottomSheet, w przeciwieństwie do onCreateDialog () , oto kod, który musisz dodać pod swoją metodą 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); }
źródło
Uproszczone i eleganckie rozwiązanie:
BottomSheetDialogFragment
można podzielić na podklasy, aby rozwiązać ten problem: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; } }
Więc rozszerz tę klasę zamiast
BottomSheetDialogFragment
tworzyć własny arkusz dolny.Uwaga
Zmień
com.google.android.material.R.id.design_bottom_sheet
na,android.support.design.R.id.design_bottom_sheet
jeśli projekt używa starych bibliotek obsługi Androida.źródło
com.google.android.material.R
teraz zamiastandroid.support.design.R
.Myślę, że te powyżej są lepsze. Niestety nie znalazłem tych rozwiązań, zanim je rozwiązałem. Ale napisz moje rozwiązanie. całkiem podobny do wszystkich.
==================================================== ================================
Mam ten sam problem. To właśnie rozwiązałem. Zachowanie jest ukryte w oknie dialogowym BottomSheetDialog, które jest dostępne, aby uzyskać zachowanie Jeśli nie chcesz zmieniać układu nadrzędnego na CooridateLayout, możesz spróbować tego.
KROK 1: dostosuj BottomSheetDialogFragment
open class CBottomSheetDialogFragment : BottomSheetDialogFragment() { //wanna get the bottomSheetDialog protected lateinit var dialog : BottomSheetDialog override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog return dialog } //set the behavior here fun setFullScreen(){ dialog.behavior.state = STATE_EXPANDED } }
KROK 2: spraw, aby Twój fragment rozszerzył ten dostosowany fragment
class YourBottomSheetFragment : CBottomSheetDialogFragment(){ //make sure invoke this method after view is built //such as after OnActivityCreated(savedInstanceState: Bundle?) override fun onStart() { super.onStart() setFullScreen()//initiated at onActivityCreated(), onStart() } }
źródło
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); } });
Spotkałem NullPointException w,
BottomSheetBehavior.from(bottomSheet)
ponieważd.findViewById(android.support.design.R.id.design_bottom_sheet)
zwraca null.To dziwne. Dodałem ten wiersz kodu do zegarków w Android Monitor w trybie DEBUG i stwierdziłem, że normalnie zwraca Framelayout.
Oto kod
wrapInBottomSheet
w 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; }
Czasami stwierdzałem, że
R.id.design_bottom_sheet
to nie jest równeandroid.support.design.R.id.design_bottom_sheet
. Mają różną wartość w różnych R.java.Więc zmieniam
android.support.design.R.id.design_bottom_sheet
naR.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); } });
Koniec z wyjątkami NullPointException.
źródło
Zastosuj
BottomsheetDialogFragment
stan wonResume
rozwiąże ten problem@Override public void onResume() { super.onResume(); if(mBehavior!=null) mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); }
onShow(DialogInterface dialog)
ipostDelayed
może powodować usterki animacjiźródło
Wszystkie wyniki przy użyciu onShow () powodują losowy błąd renderowania, gdy wyświetlana jest klawiatura programowa. Zobacz zrzut ekranu poniżej - okno dialogowe Arkusz dolny nie znajduje się na dole ekranu, ale jest umieszczone tak, jak została wyświetlona klawiatura. Ten problem nie występuje zawsze, ale dość często.
AKTUALIZACJA
Moje rozwiązanie z odbiciem członka prywatnego jest niepotrzebne. Lepszym rozwiązaniem jest użycie postDelayed (z około 100 ms) do tworzenia i wyświetlania okna dialogowego po ukryciu miękkiej klawiatury. Wtedy powyższe rozwiązania z onShow () są w porządku.
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);
Wdrażam więc inne rozwiązanie, ale wymaga to użycia refleksji, ponieważ BottomSheetDialog ma wszystkie składowe jako prywatne. Ale rozwiązuje błąd renderowania. BottomSheetDialogFragment to tylko klasa AppCompatDialogFragment z metodą onCreateDialog, która tworzy BottomSheetDialog. Tworzę własne dziecko AppCompatDialogFragment, które tworzy moją klasę rozszerza BottomSheetDialog i rozwiązuje dostęp do prywatnego elementu zachowania i ustawiam go w metodzie onStart na stan 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()); } .... }
źródło
Najłatwiejszy sposób, który zaimplementowałem, jest taki, jak poniżej, tutaj znajdujemy android.support.design.R.id.design_bottom_sheet i ustawiamy stan dolnego arkusza jako EXPANDED .
Bez tego mój dolny arkusz zawsze był w stanie ZWINIĘTY, jeśli wysokość widoku jest większa niż 0,5 wysokości ekranu i muszę ręcznie przewijać, aby wyświetlić pełny dolny arkusz.
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 } }
źródło
Podobnie jak odpowiedź uregentx , w kotlin możesz zadeklarować klasę fragmentu, która rozszerza się z
BottomSheetDialogFragment
, a kiedy widok jest tworzony, możesz ustawić domyślny stan detektora okna dialogowego po wyświetleniu okna dialogowego.class FragmentCreateGroup : BottomSheetDialogFragment() { ... override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? { // Set dialog initial state when shown dialog?.setOnShowListener { val bottomSheetDialog = it as BottomSheetDialog val sheetInternal: View = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet)!! BottomSheetBehavior.from(sheetInternal).state = BottomSheetBehavior.STATE_COLLAPSED } val view = inflater.inflate(R.layout.fragment_create_group, container, false) ... return view } }
Pamiętaj o implementacji Material Design w Gradle.
Zapoznaj się również z materiałami referencyjnymi na dole strony
źródło
dialog?
pochodzi zmienna w onCreateView?dialog
jest właściwością klasyDialogFragment
, w rzeczywistości jest Getter. W tym przykładzie użyłem tego gettera, aby pobrać bieżącą instancję DialogFragment isetOnShowListener
do niej. ByćactionBar
możeactionBar?.subtitle = "abcd"
Moja odpowiedź jest mniej więcej taka sama, jak większość powyższych odpowiedzi, z niewielką modyfikacją. Zamiast używać findViewById, aby najpierw znaleźć dolny widok arkusza, wolałem nie kodować na stałe identyfikatorów zasobów widoku struktury, ponieważ mogą się one zmienić w przyszłości.
setOnShowListener(dialog -> { BottomSheetBehavior bottomSheetBehavior = ((BottomSheetDialog)dialog).getBehavior(); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); });
źródło
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return super.onCreateDialog(savedInstanceState).apply { setOnShowListener { (this@TipsBottomDialogFragment.dialog as BottomSheetDialog).behavior.setState( BottomSheetBehavior.STATE_EXPANDED ) } } }
źródło
Wysyłając to tutaj przyszłym czytelnikom, ponieważ myślę, że możemy użyć innego rozwiązania.
Próbowałem rozwiązać ten sam problem, który opisałeś za pomocą pliku
BottomSheetDialog
.Nie lubię używać wewnętrznych identyfikatorów Androida i właśnie odkryłem, że istnieje metoda
BottomSheetDialog
getBehavior
, której możesz użyć:Możesz użyć tego w swoim
BottomSheetDialog
:behavior.state = BottomSheetBehavior.STATE_EXPANDED
Za pomocą
BottomSheetDialogFragment
you możesz zrobić to samo, rzutując okno dialogowe z tego DialogFragment doBottomSheetDialog
.źródło
BottomSheetDialogFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED }
lub gdy jesteś gotowy do pokazania:
private fun onContentLoaded(items: List<Any>) { adapter.submitList(items) (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED }
źródło
W klasie Kotlin BottomSheetDialogFragment nadpisz onCreateDialog jak poniżej
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog bottomSheetDialog.setOnShowListener { val bottomSheet = bottomSheetDialog.findViewById<FrameLayout>( com.google.android.material.R.id.design_bottom_sheet ) val behavior = BottomSheetBehavior.from(bottomSheet!!) behavior.skipCollapsed = true behavior.state = BottomSheetBehavior.STATE_EXPANDED } return bottomSheetDialog }
źródło