Подтвердить что ты не робот

Динамически менять высоту BottomSheetBehavior

Я использую BottomSheetBehavior из недавно выпущенного AppCompat v23.2 от Google. Высота моего нижнего листа зависит от содержимого, отображаемого внутри нижнего листа (аналогично тому, что делает Google в приложении "Карты" ).

Он отлично работает с первоначально загруженными данными, но мое приложение меняет содержимое, отображаемое во время выполнения, и когда это происходит, нижний лист сохраняет на нем прежнюю высоту, что либо приводит к неиспользуемому пространству внизу, либо к разрезу.

Есть ли способ сообщить макет нижнего листа для пересчета высоты, используемой для расширенного состояния (когда высота ViewGroup установлена ​​на MATCH_HEIGHT) или каким-либо способом вручную установить требуемую высоту?


EDIT: Я также попытался вручную вызвать invalidate() на ViewGroup и родительский элемент, но без каких-либо успехов.

4b9b3361

Ответ 1

У меня была та же проблема с RelativeLayout как мой нижний лист. Высота не будет пересчитана. Я должен был прибегнуть к установке высоты по новому пересчитанному значению и вызвать BottomSheetBehavior.onLayoutChild.

Это мое временное решение:

coordinatorLayout = (CoordinatorLayout)findViewById(R.id.coordinator_layout);
bottomSheet = findViewById(R.id.bottom_sheet);

int accountHeight = accountTextView.getHeight();
accountTextView.setVisibility(View.GONE);

bottomSheet.getLayoutParams().height = bottomSheet.getHeight() - accountHeight;
bottomSheet.requestLayout();
behavior.onLayoutChild(coordinatorLayout, bottomSheet, ViewCompat.LAYOUT_DIRECTION_LTR);

Ответ 2

Вы можете использовать BottomSheetBehavior#setPeekHeight для этого.

FrameLayout bottomSheet = (FrameLayout) findViewById(R.id.bottom_sheet);
BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setPeekHeight(newHeight);

Это не автоматически перемещает нижний лист на высоту заглядывания. Вы можете вызвать BottomSheetBehavior#setState, чтобы настроить нижний лист на новую высоту заглядывания.

behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);

Ответ 3

Хотя проблема была решена в библиотеке поддержки >= 24.0.0, если по какой-то причине вам все равно придется использовать более старую версию, это обходное решение.

mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull final View bottomSheet, int newState) {
            bottomSheet.post(new Runnable() {
                @Override
                public void run() {
                    //workaround for the bottomsheet  bug
                    bottomSheet.requestLayout();
                    bottomSheet.invalidate();
                }
            });
        }

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

Ответ 4

Я столкнулся с такой же проблемой, пытаясь обновить высоту заглядывания на основе ее содержимого, была найдена высота от предыдущего макета. Это имеет смысл, поскольку новый макет еще не состоялся. По проводке в потоке пользовательского интерфейса высота макета вычисляется после нового макета, и выполняется другой запрос макета, чтобы обновить нижний лист до нужной высоты.

void show() {
    setVisibility(View.VISIBLE);
    post(new Runnable() {
        @Override
        public void run() {
            mBottomSheetBehavior.setPeekHeight(findViewById(R.id.sheetPeek).getHeight());
            requestLayout();
        }
    })
}

Ответ 5

У меня возникла такая же проблема, когда я использовал recyclerview внутри BottomSheet, и элементы менялись динамически. Как отметил @sosite в своем комментарии, проблема регистрируется, и они исправили ее в последней версии. Журнал проблем здесь

Просто обновите свою библиотеку поддержки дизайна до версии 24.0.0 и проверьте.

Ответ 6

Я следовал совету @HaraldUnander, и он дал мне идею, которая действительно сработала. Если вы запустили поток (не смог заставить его работать с методом post как он) после того, как BottomSheetBehavior.state программно STATE_COLLAPSED на STATE_COLLAPSED, то вы уже можете получить высоту ваших представлений и установить peekHeight зависимости от его содержимого.

Итак, сначала вы устанавливаете BottomSheetBehavior:

BottomSheetBehavior.from(routeCaptionBottomSheet).state = BottomSheetBehavior.STATE_COLLAPSED

И тогда вы устанавливаете peekHeight динамически:

thread {
    activity?.runOnUiThread {
        val dynamicHeight = yourContainerView.height
        BottomSheetBehavior.from(bottomSheetView).peekHeight = dynamicHeight
    }
}

Если используется Java (я использую Kotlin с Anko для потоков), это может сделать:

new Thread(new Runnable() {
    public void run() {
        val dynamicHeight = yourContainerView.height
        BottomSheetBehavior.from(bottomSheetView).peekHeight = dynamicHeight
    }
}).start();