Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Support BottomSheetBehavior can't be dynamic?

I'm using Bottom Sheet from Android support library like this:

XML:

<LinearLayout
    android:id="@+id/bottomSheetLinearLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/fourth_white"
    android:orientation="vertical"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior" />

I add child views to LinearLayout:

bottomSheet.addView(actionButtonView);

After I've finished adding child views, I initialize BottomSheetBehavior and expand it:

BottomSheetBehavior sheetBehavior = BottomSheetBehavior.from(bottomSheet);
sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);

This doesn't work. Nothing shows. Even if I preset the LinearLayout height inside XML, it's just all white.

If I add all the child views inside LinearLayout in XML, then everything works fine. It just doesn't work when I try to dynamically add views programatically.

Anyone had any similar issues?

like image 215
Guy Avatar asked Mar 25 '16 11:03

Guy


2 Answers

Troubles with dynamic content on BottomSheetBehavior related to implementation of it's expanded size calculation. BottomSheetBehavior calculates expanded size in onLayoutChild method. But when you change content of sheet layout process launches asynchronous. Even if you call RequestLayout or something similar. So consequence of calls is like this:

  1. BottomSheetBehavior have old expanded size (in your case I think it is zero)
  2. You add content to BottomSheet. Expanded size is still old.
  3. You call SetState to EXPANDED. BottomSheetBehavior still remember old expanded size and launches animation to that size. State changed to STATE_SETTLING!
  4. onLayoutChild called and BottomSheetBehavior calculates new expanded size. But animation is already in progress and state is STATE_SETTLING so BottomSheetBehavior do not change its size
  5. Animation finished. Size of BottomSheet is old. State changed to EXPANDED but BottomSheetBehavior "forgot" that expanded size was changed during animation.

It is surely the bug of BottomSheetBehaviour implementation.

In my project I found such workaround:

private void showPanel(final View panelContent) {
    if (panelBehavior.getState()!=BottomSheetBehavior.STATE_EXPANDED) {
        panelBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(final View bottomSheet, int newState) {
                if (newState==BottomSheetBehavior.STATE_EXPANDED) {
                    panelBehavior.setBottomSheetCallback(null);
                    contentView.removeAllViews();
                    contentView.addView(panelContent);
                    panelView.setVisibility(View.VISIBLE);

                }
            }

            @Override
            public void onSlide(View bottomSheet, float slideOffset) {

            }
        });
        panelBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
        return;
    }
    contentView.removeAllViews();
    contentView.addView(panelContent);
    panelView.setVisibility(View.VISIBLE);
}

private void hidePanel() {
    panelBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    panelView.setVisibility(View.GONE);
    contentView.removeAllViews();
}

So when you need to show BottomSheet with new content call ShowPanel. When you need to completely hide BottomSheet call hidePanel (if you need to hide it in your project. If not you could remove setVisibility from methods).

The idea of workaround is to never change content of BottomSheet when BottomSheetBehavior is not in expanded state. If state is not expanded just change it to expanded, wait until animation finished and only then change content.

like image 191
Volchik Avatar answered Sep 21 '22 15:09

Volchik


Try to post runnable to view's message queue:

bottomSheet.post(new Runnable() {
    @Override
    public void run() {
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }
});

Or with retrolambda:

bottomSheet.post(() -> bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED));
like image 43
Stas Parshin Avatar answered Sep 17 '22 15:09

Stas Parshin