简体   繁体   中英

Set peek height programmatically in BottomSheetDialogFragment

I have a BottomSheetDialogFragment that I want to be able to show on any screen. I've spent the day trying to programmatically change the peek height of the sheet, but nothing seems to be changing it.

Here is my layout, bottom_sheet.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical"
        app:behavior_hideable="true"
        app:behavior_peekHeight="96dp"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <androidx.core.widget.NestedScrollView
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

</LinearLayout>

You will notice I have an empty NestedScrollView . This is because I have made my content customizable when I show the bottom sheet on different screens, so I load a custom layout into it through code.

Here is my fragment class:

public class BottomSheetFragment extends BottomSheetDialogFragment {

    private LinearLayout bottomSheet;
    private NestedScrollView contentView;

    public BottomSheetFragment() {

    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.bottom_sheet, container, false);
    }

    @Override
    public void onViewCreated(@NotNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        bottomSheet = view.findViewById(R.id.bottom_sheet);
        contentView = view.findViewById(R.id.content);
    }

    // Set the layout of the NestedScrollView by passing a layout ID
    public void setLayout(int layoutId) {
        if (contentView != null) {
            contentView.removeAllViews();

            View view = getLayoutInflater().inflate(layoutId, contentView, false);

            if (view != null) {
                contentView.addView(view);
            }
        }
    }
}

Then, where I want to show the bottom sheet, I do:

BottomSheetFragment bottomSheetFragment = new BottomSheetFragment();
bottomSheetFragment.show(getSupportFragmentManager(), bottomSheetFragment.getTag());

I want the peek height of the sheet to be 64dp from the top of the screen. How and where would I do this programmatically?

I also found that, even if I change the value of app:behavior_peekHeight="96dp" in the layout to something like 500dp, it still doesn't change anything when I show the sheet.

There is no view element in your bottom_sheet. Thats why you dont see any change when play around with peekheight .

Set some height to bottom_sheet to view changes. If you set the height (300) for example, you will clearly see the peek height taking effect.

For example,

<LinearLayout
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="@color/colorPrimary"
            android:orientation="vertical"
            android:id="@+id/bottom_sheet"
            app:layout_behavior="@string/bottom_sheet_behavior"
            app:behavior_peekHeight="96dp"
            app:behavior_hideable="true">

            <androidx.core.widget.NestedScrollView
                android:id="@+id/content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </LinearLayout>

will Result in

在此处输入图像描述

To set peekheight programatically

First you have to put your bottomsheet in coordinate layout like that

<androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="@color/colorPrimary"
            android:orientation="vertical"
            android:id="@+id/bottom_sheet"
            app:layout_behavior="@string/bottom_sheet_behavior"
            app:behavior_peekHeight="96dp"
            app:behavior_hideable="true">

            <androidx.core.widget.NestedScrollView
                android:id="@+id/content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </LinearLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

In your class, you do that.

@Override
    public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        View bottomSheet = view.findViewById(R.id.bottom_sheet);
        BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setPeekHeight(150); 
    }

You can set state STATE_EXPANDED on BottomSheetShow. here's my working code snippet.

@Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

        dialog.setOnShowListener((DialogInterface.OnShowListener) dialog1 -> {
            BottomSheetDialog d = (BottomSheetDialog) dialog1;
            FrameLayout bottomSheet = (FrameLayout) d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
            if (bottomSheet != null)
                BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
        });

        return dialog;
    }

You can set the peek height to your bottom sheet by getting its reference by override OnCreateDialog method inside your BottomSheetFragment

public class BottomSheetFragment extends BottomSheetDialogFragment {

    private LinearLayout bottomSheet;
    private NestedScrollView contentView;

    public BottomSheetFragment() {

    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.bottom_sheet, container, false);
    }

    @Override
    public void onViewCreated(@NotNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        bottomSheet = view.findViewById(R.id.bottom_sheet);
        contentView = view.findViewById(R.id.content);
    }

    /**
     * 
     * Your code to modify the bottom sheet behavior to set peek height which will be used in collapsed state
     * Here I set it to 80 percent of height of my screen
     * You can directly setPeekHeight() to your requirement
     */
    @NonNull @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog bottom_dialog = (BottomSheetDialog) dialog;

                FrameLayout bottomSheet = (FrameLayout) bottom_dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
                assert bottomSheet != null;
                //BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
                DisplayMetrics displayMetrics = requireActivity().getResources().getDisplayMetrics();
                int height = displayMetrics.heightPixels;
                int maxHeight = (int) (height*0.80);
                BottomSheetBehavior.from(bottomSheet).setPeekHeight(maxHeight);
            }
        });

        return dialog;
    }

    // Set the layout of the NestedScrollView by passing a layout ID
    public void setLayout(int layoutId) {
        if (contentView != null) {
            contentView.removeAllViews();

            View view = getLayoutInflater().inflate(layoutId, contentView, false);

            if (view != null) {
                contentView.addView(view);
            }
        }
    }
}

To set the peek height programmatically, you can:

  1. Override onCreateDialog in your BottomSheetDialogFragment
  2. Cast as BottomSheetDialog
  3. Call setPeekHeight(int, boolean) on the behavior ( BottomSheetBehavior )
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return super.onCreateDialog(savedInstanceState).apply {
        (this as? BottomSheetDialog)
                ?.behavior
                ?.setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO, true)
    }
}

The BottomSheetBehavior.PEEK_HEIGHT_AUTO sets a 16:9 ratio, and true is whether to animate.

You have to overrride onCreateDialog and cast the super.onCreateDialog(savedInstanceState) to BottomSheetDialog that content the methd behavior.setPeekHeight(Int)

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply {
      behavior.setPeekHeight(resources.displayMetrics.heightPixels / 2)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM