Android BottomSheetDialogFragment не полностью расширяется
У меня есть следующая реализация тестового нижнего листа.
Когда я устанавливаю peehHight на значение меньше 500, он работает. После некоторого значения любое увеличение высоты зазора не изменит способ расширения нижнего листа. Он просто остается там только вручную. Как мы устанавливаем peekHeight программно, чтобы гарантировать, что нижний лист будет автоматически расширен до высоты заглядывания.
![введите описание изображения здесь]()
bottom_sheet_dialog_main
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/locUXCoordinatorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/locUXView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:orientation="vertical"
app:behavior_hideable="false"
app:behavior_peekHeight="0dp"
app:layout_behavior="@string/bottom_sheet_behavior">
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="1 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="2 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="3 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="4 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="5 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="6 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="7 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="8 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="9 Value" />
<TextView
android:layout_width="match_parent"
android:layout_height="100dp"
android:text="First Value" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Java-код
public class MyBottomSheetDialogFragment extends BottomSheetDialogFragment {
private static BottomSheetBehavior bottomSheetBehavior;
private static View bottomSheetInternal;
private static MyBottomSheetDialogFragment INSTANCE;
@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;
CoordinatorLayout coordinatorLayout = (CoordinatorLayout)d.findViewById(R.id.locUXCoordinatorLayout);
bottomSheetInternal = d.findViewById(R.id.locUXView);
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetInternal);
bottomSheetBehavior.setPeekHeight(bottomSheetInternal.getHeight());
bottomSheetInternal.requestLayout();
coordinatorLayout.getLayoutParams().height = bottomSheetInternal.getHeight();
Toast.makeText(getActivity(), "Height is" + bottomSheetInternal.getHeight() + " " + coordinatorLayout.getLayoutParams().height, Toast.LENGTH_LONG).show();
}
});
INSTANCE = this;
return inflater.inflate(R.layout.bottom_sheet_dialog_main, container, false);
}
}
Ответы
Ответ 1
Более глубокая проверка пользовательского интерфейса, мы обнаруживаем, что есть еще один CoordinatorLayout
, который обертывает наш координатор. Родительский CoordinatorLayout
имеет FrameLayout
с BottomSheetBehavior
с id design_bottom_sheet
. Высота заглядывания, установленная в нашем коде выше, ограничивалась из-за высоты match_parent
FrameLayout
с идентификатором design_bottom_sheet
Установив высоту peek FrameLayout
с идентификатором design_bottom_sheet, эта проблема была решена.
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;
coordinatorLayout = (CoordinatorLayout) d.findViewById(R.id.locUXCoordinatorLayout);
bottomSheetInternal = d.findViewById(R.id.locUXView);
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetInternal);
bottomSheetBehavior.setHidable(false);
BottomSheetBehavior.from((View)coordinatorLayout.getParent()).setPeekHeight(bottomSheetInternal.getHeight());
bottomSheetBehavior.setPeekHeight(bottomSheetInternal.getHeight());
coordinatorLayout.getParent().requestLayout();
}
});
Ответ 2
Использование этого кода в onCreateView.
getDialog().setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
BottomSheetDialog d = (BottomSheetDialog) dialog;
FrameLayout bottomSheet = (FrameLayout) d.findViewById(R.id.design_bottom_sheet);
CoordinatorLayout coordinatorLayout = (CoordinatorLayout) bottomSheet.getParent();
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bottomSheetBehavior.setPeekHeight(bottomSheet.getHeight());
coordinatorLayout.getParent().requestLayout();
}
});
Ответ 3
Я нашел другое решение. Возможно, для будущих читателей это может быть полезно.
@Override
public void setupDialog(Dialog dialog, int style) {
super.setupDialog(dialog, style);
final View root = View.inflate(getContext(), R.layout.fragment_bottom_sheet_choose_time, null);
dialog.setContentView(root);
initView(root);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) root.getParent()).getLayoutParams();
CoordinatorLayout.Behavior behavior = params.getBehavior();
if (behavior != null && behavior instanceof BottomSheetBehavior) {
mBottomSheetBehavior = (BottomSheetBehavior) behavior;
mBottomSheetBehavior.setBottomSheetCallback(mBottomSheetBehaviorCallback);
root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int height = root.getMeasuredHeight();
mBottomSheetBehavior.setPeekHeight(height);
}
});
}
}
Как упоминалось в @Anthonyeef, здесь ViewTreeObserver
направлена на то, чтобы получить точную высоту измерения после того, как представление действительно измерено, и GlobalOnLayoutListener
удалено для лучшей производительности.
Но, пожалуйста, перед использованием в производстве, протестируйте это решение на разных устройствах и экранах, потому что, если ваш контент в нижнем листе выше вашего экрана, он может вызвать некоторые странные поведения при прохождении.
Ответ 4
Спасибо @athysirus за аккуратный подход. Вот версия, на которой я остановился, на случай, если кто-то захочет получить работающий образец kotlin.
Важно отметить, что вы должны также удалить слушателя глобального макета, как только это будет сделано.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
val bottomSheet = (dialog as BottomSheetDialog).findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
BottomSheetBehavior.from<View>(bottomSheet).apply {
state = BottomSheetBehavior.STATE_EXPANDED
peekHeight = 0
}
view.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
Ответ 5
Решение в Kotlin, вдохновленное Nandish A постом, более подробно. Сначала макет:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/container_root"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:behavior_hideable="false"
app:behavior_peekHeight="0dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<!-- content of the bottom sheet -->
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
А затем вставьте это в свой BottomSheetDialogFragment
:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// ...
dialog.setOnShowListener {
val root = dialog.find<CoordinatorLayout>(R.id.container_root)
val bottomSheetInternal = root.find<ConstraintLayout>(R.id.bottom_sheet)
val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetInternal)
bottomSheetBehavior.isHideable = false
BottomSheetBehavior.from(root.parent as View).peekHeight = root.height
bottomSheetBehavior.peekHeight = root.height
root.parent.requestLayout()
}
// ...
}
Ответ 6
вот как я установил peek_height
и layout_height
в нижний вид листа
dialog?.setOnShowListener {
val dialog = dialog as BottomSheetDialog
val bottomSheet = dialog.findViewById<FrameLayout>(R.id.design_bottom_sheet)
val coordinatorLayout = bottomSheet?.parent as? CoordinatorLayout
val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheet?.viewTreeObserver?.addOnGlobalLayoutListener {
bottomSheet.viewTreeObserver.removeOnGlobalLayoutListener {}
bottomSheetBehavior.peekHeight = getPopupHeight(.5f)
val params = bottomSheet.layoutParams
params.height = getPopupHeight(1f)
bottomSheet.layoutParams = params
coordinatorLayout?.parent?.requestLayout()
}
}
этот метод для получения процента от высоты экрана
private fun getPopupHeight(percent: Float): Int {
val displayMetrics = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(displayMetrics)
return (displayMetrics.heightPixels * percent).toInt()
}