Поддержка Android BottomSheetBehavior не может быть динамической?

Я использую нижний лист из библиотеки поддержки Android следующим образом:

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" />

я добавляю дочерние представления в LinearLayout:

bottomSheet.addView(actionButtonView);

после того, как я закончил добавлять дочерние представления, я инициализирую BottomSheetBehavior и расширяю его:

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

Это не сработает. Ничего не видно. Даже если я задал высоту LinearLayout внутри XML, она просто белая.

Если я добавлю все дочерние представления внутри LinearLayout в XML, то все работать отлично. Он просто не работает, когда я пытаюсь динамически добавлять представления программно.

У кого-нибудь были подобные проблемы?

2 ответов


проблемы с динамическим контентом на BottomSheetBehavior, связанные с реализацией вычисления расширенного размера. BottomSheetBehavior вычисляет расширенный размер в методе onLayoutChild. Но при изменении содержимого макета листа процесс запускается асинхронно. Даже если вы вызываете RequestLayout или что-то подобное. Поэтому следствие звонков выглядит так:

  1. BottomSheetBehavior имеют старый расширенный размер (в вашем случае я думаю, что он равен нулю)
  2. добавить содержимое BottomSheet. Расширенный размер все еще стар.
  3. вы вызываете SetState в расширенный. BottomSheetBehavior все еще помнит старый расширенный размер и запускает анимацию до этого размера. Состояние изменено на STATE_SETTLING!
  4. onlayoutchild вызывается и BottomSheetBehavior вычисляет новый расширенный размер. Но анимация уже выполняется, и состояние STATE_SETTLING так BottomSheetBehavior не изменить его размер
  5. анимация закончена. Размер BottomSheet старый. Состояние изменено на Расширенный, но BottomSheetBehavior "забыл", что расширенный размер был изменен во время анимации.

это, безусловно, ошибка реализации BottomSheetBehaviour.

в моем проекте я нашел такое решение:

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();
}

поэтому, когда вам нужно показать BottomSheet с новым содержимым, вызовите ShowPanel. Когда вам нужно полностью скрыть BottomSheet вызовите hidePanel (если вам нужно скрыть его в своем проекте. Если нет, вы можете удалить setVisibility из методы.)

идея обходного пути-никогда не изменять содержимое BottomSheet, когда BottomSheetBehavior не находится в расширенном состоянии. Если состояние не расширено, просто измените его на расширенное, дождитесь завершения анимации и только затем измените содержимое.


попробуйте опубликовать runnable для просмотра очереди сообщений:

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

или с retrolambda:

bottomSheet.post(() -> bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED));