"Perhatikan bahwa Anda tidak dapat memanggil metode sebelum melihat tata letak."
Teks di atas adalah petunjuknya.
Dialog memiliki pendengar yang diaktifkan setelah dialog ditampilkan . Dialog tidak dapat ditampilkan jika tidak ditata.
Jadi, di onCreateDialog()
modal lembar bawah Anda ( BottomSheetFragment
), tepat sebelum mengembalikan dialog (atau di mana saja, setelah Anda memiliki referensi ke dialog), panggil:
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);
}
});
Dalam kasus saya, kebiasaan saya BottomSheet
ternyata:
@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;
}
}
Beri tahu saya jika ini membantu.
MEMPERBARUI
Perhatikan bahwa Anda juga dapat mengganti BottomSheetDialogFragment
sebagai:
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;
}
}
Tapi saya benar-benar tidak melihat mengapa ada orang yang ingin melakukan itu karena pangkalan BottomSheetFragment
tidak melakukan apa pun selain mengembalikan a BottomSheetDialog
.
UPDATE UNTUK ANDROIDX
Saat menggunakan AndroidX, sumber daya yang sebelumnya ditemukan di android.support.design.R.id.design_bottom_sheet
sekarang dapat ditemukan di com.google.android.material.R.id.design_bottom_sheet
.
BottomSheetDialogFragment
tersendat (tampak melewatkan bingkai dalam animasi pembuka) saat beralih dari perilaku diciutkan ke diperluas. Sunting: Diuji ini pada perangkat Android Marshmallow dan KitKatandroid.support.design.R
setelah memperbarui pustaka dukungan?android.support.design.R
, seperti @natario. Saya menggunakanimplementation "com.google.android.material:material:1.0.0"
. Saya juga menggunakan AndroidX dalam proyek ini.com.google.android.material.R.id.design_bottom_sheet
jawaban efeturi bagus, namun, jika Anda ingin menggunakan onCreateView () untuk membuat BottomSheet Anda, sebagai lawan menggunakan onCreateDialog () , berikut adalah kode yang perlu Anda tambahkan di bawah metode 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); }
sumber
Solusi sederhana dan elegan:
BottomSheetDialogFragment
bisa menjadi subclass untuk mengatasi ini: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; } }
Jadi perluas kelas ini daripada
BottomSheetDialogFragment
membuat lembar bawah Anda sendiri.Catatan
Ubah
com.google.android.material.R.id.design_bottom_sheet
keandroid.support.design.R.id.design_bottom_sheet
jika proyek Anda menggunakan pustaka dukungan Android lama.sumber
com.google.android.material.R
sekarang, bukanandroid.support.design.R
.Saya pikir yang di atas lebih baik. Sayangnya saya tidak menemukan solusi itu sebelum saya menyelesaikannya. Tapi tulis solusi saya. sangat mirip dengan semua.
================================================== ================================
Saya menghadapi masalah yang sama. Inilah yang saya pecahkan. Perilaku disembunyikan di BottomSheetDialog, yang tersedia untuk mendapatkan perilaku Jika Anda tidak ingin mengubah tata letak induk menjadi CooridateLayout, Anda dapat mencoba ini.
LANGKAH 1: sesuaikan 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 } }
LANGKAH 2: buat fragmen Anda memperluas fragmen yang disesuaikan ini
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() } }
sumber
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); } });
Saya bertemu NullPointException
BottomSheetBehavior.from(bottomSheet)
karenad.findViewById(android.support.design.R.id.design_bottom_sheet)
mengembalikan null.Ini aneh. Saya menambahkan baris kode ini ke Jam di Android Monitor dalam mode DEBUG dan menemukan itu mengembalikan Framelayout secara normal.
Berikut kode
wrapInBottomSheet
di 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; }
Kadang-kadang, saya menemukan bahwa
R.id.design_bottom_sheet
itu tidak sama denganandroid.support.design.R.id.design_bottom_sheet
. Mereka memiliki nilai yang berbeda pada R.java yang berbeda.Jadi saya berubah
android.support.design.R.id.design_bottom_sheet
menjadiR.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); } });
Tidak ada lagi NullPointException sekarang.
sumber
Terapkan
BottomsheetDialogFragment
negara bagianonResume
akan menyelesaikan masalah ini@Override public void onResume() { super.onResume(); if(mBehavior!=null) mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); }
onShow(DialogInterface dialog)
danpostDelayed
dapat menyebabkan kesalahan animasisumber
Semua hasil dengan menggunakan onShow () menyebabkan bug render acak saat keyboard lunak ditampilkan. Lihat tangkapan layar di bawah - Dialog BottomSheet tidak berada di bagian bawah layar tetapi ditempatkan seperti keyboard ditampilkan. Masalah ini tidak selalu terjadi tetapi cukup sering.
MEMPERBARUI
Solusi saya dengan refleksi anggota pribadi tidak perlu. Menggunakan postDelayed (dengan sekitar 100 ms) untuk membuat dan menampilkan dialog setelah sembunyikan keyboard lunak adalah solusi yang lebih baik. Maka solusi di atas dengan onShow () tidak masalah.
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);
Jadi saya menerapkan solusi lain, tetapi memerlukan penggunaan refleksi, karena BottomSheetDialog memiliki semua anggota sebagai pribadi. Tapi itu memecahkan bug render. Kelas BottomSheetDialogFragment hanya AppCompatDialogFragment dengan metode onCreateDialog yang membuat BottomSheetDialog. Saya membuat anak AppCompatDialogFragment sendiri yang membuat kelas saya memperluas BottomSheetDialog dan yang memecahkan akses ke anggota perilaku pribadi dan menetapkannya dalam metode onStart ke status 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()); } .... }
sumber
Cara termudah yang saya terapkan adalah seperti di bawah ini, Di sini kita menemukan android.support.design.R.id.design_bottom_sheet dan mengatur status lembar bawah sebagai DIPERLUAS .
Tanpa ini, lembaran bawah saya selalu macet dalam keadaan TERTUTUP jika tinggi tampilan lebih dari 0,5 tinggi layar dan saya harus menggulir secara manual untuk melihat lembaran bawah penuh.
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 } }
sumber
Mirip dengan jawaban uregentx , di kotlin , Anda dapat mendeklarasikan kelas fragmen yang merupakan turunan dari
BottomSheetDialogFragment
, dan saat tampilan dibuat, Anda dapat menyetel status default pendengar dialog setelah dialog ditampilkan.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 } }
Ingat menggunakan implementasi desain material di gradle.
Lihat juga referensi desain material Lembaran Bawah
sumber
dialog?
asalnya variabel di onCreateView?dialog
adalah properti kelasDialogFragment
, sebenarnya adalah seorang Getter. Dalam contoh ini saya menggunakan getter itu untuk mendapatkan instance DialogFragment saat ini dansetOnShowListener
untuk itu. Mungkin Anda telah menggunakan instruksi semacam itu dalam proyek Anda, misalnya dalam suatu aktivitas, untuk mengaksesactionBar
pengambil bilah tindakan digunakan, sehingga Anda dapat memodifikasi komponen itu, misalnyaactionBar?.subtitle = "abcd"
Jawaban saya kurang lebih sama dengan kebanyakan jawaban diatas dengan sedikit modifikasi. Alih-alih menggunakan findViewById untuk pertama kali menemukan tampilan lembar bawah, saya lebih suka untuk tidak membuat kode keras id sumber daya tampilan kerangka kerja karena mereka mungkin berubah di masa depan.
setOnShowListener(dialog -> { BottomSheetBehavior bottomSheetBehavior = ((BottomSheetDialog)dialog).getBehavior(); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); });
sumber
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return super.onCreateDialog(savedInstanceState).apply { setOnShowListener { (this@TipsBottomDialogFragment.dialog as BottomSheetDialog).behavior.setState( BottomSheetBehavior.STATE_EXPANDED ) } } }
sumber
Posting ini di sini untuk pembaca yang akan datang, karena saya pikir kita bisa menggunakan solusi lain.
Saya mencoba memecahkan masalah yang sama yang Anda gambarkan dengan file
BottomSheetDialog
.Saya tidak suka menggunakan id Android internal dan saya baru saja menemukan ada metode di dalamnya
BottomSheetDialog
getBehavior
yang dapat Anda gunakan:Anda dapat menggunakan ini di dalam
BottomSheetDialog
:behavior.state = BottomSheetBehavior.STATE_EXPANDED
Menggunakan
BottomSheetDialogFragment
Anda dapat melakukan casting yang sama dialog dari DialogFragment itu keBottomSheetDialog
.sumber
BottomSheetDialogFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED }
atau saat siap untuk ditampilkan:
private fun onContentLoaded(items: List<Any>) { adapter.submitList(items) (dialog as? BottomSheetDialog)?.behavior?.state = STATE_EXPANDED }
sumber
Di kelas Kotlin BottomSheetDialogFragment Anda, ganti onCreateDialog seperti di bawah ini
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 }
sumber