Как программно установить высоту AppBarLayout в библиотеке поддержки Android версии 24.0.0?

При обновлении библиотеки поддержки Android версии 23.4.0 до версии 24.0.0 программная установка высоты 0 для AppBarLayout перестала работать:

appBayLayout.setElevation(0);

Это работает при установке высоты в XML.


person bryant1410    schedule 23.06.2016    source источник


Ответы (3)


Изменить

AppBarLayout из версии 24.0.0 использует StateListAnimator, который определяет высоту в зависимости от его состояния. Таким образом, использование setElevation не будет иметь никакого эффекта, если используется StateListAnimator (что происходит по умолчанию). Установите elevation через XML или программно (оба для API >= 21):

StateListAnimator stateListAnimator = new StateListAnimator();
stateListAnimator.addState(new int[0], ObjectAnimator.ofFloat(view, "elevation", 0));
appBarLayout.setStateListAnimator(stateListAnimator);

Старый ответ

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

Здесь есть обходной путь:

setDefaultAppBarLayoutStateListAnimator(appBarLayout, 0);

@SuppressLint("PrivateResource")
private static void setDefaultAppBarLayoutStateListAnimator(final View view, final float targetElevation) {
    final StateListAnimator sla = new StateListAnimator();

    // Enabled, collapsible and collapsed == elevated
    sla.addState(new int[]{android.R.attr.enabled, android.support.design.R.attr.state_collapsible,
            android.support.design.R.attr.state_collapsed},
            ObjectAnimator.ofFloat(view, "elevation", targetElevation));

    // Enabled and collapsible, but not collapsed != elevated
    sla.addState(new int[]{android.R.attr.enabled, android.support.design.R.attr.state_collapsible,
            -android.support.design.R.attr.state_collapsed},
            ObjectAnimator.ofFloat(view, "elevation", 0f));

    // Enabled but not collapsible == elevated
    sla.addState(new int[]{android.R.attr.enabled, -android.support.design.R.attr.state_collapsible},
            ObjectAnimator.ofFloat(view, "elevation", targetElevation));

    // Default, none elevated state
    sla.addState(new int[0], ObjectAnimator.ofFloat(view, "elevation", 0));

    view.setStateListAnimator(sla);
}

Это взято из того, что делает конструктор, вызывая метод в классе ViewUtilsLollipop в версии 24.0.0.

person bryant1410    schedule 23.06.2016
comment
Какой view используется в вашем примере stateListAnimator.addState(new int[0], ObjectAnimator.ofFloat(view, "elevation", 0));? - person Volodymyr; 03.12.2016
comment
@VolodymyrKhodonovych, переданный в качестве параметра - person bryant1410; 03.12.2016
comment
У меня есть ошибка в android 21, подобная этой › JNI ОБНАРУЖЕНА ОШИБКА В ПРИЛОЖЕНИИ: не могу вызвать void › android.view.View.setElevation(float) для нулевого объекта - person Volodymyr; 03.12.2016
comment
@VolodymyrKhodonovych кажется, что ссылка на ваш объект просмотра имеет значение null - person bryant1410; 03.12.2016

Еще одно возможное решение — добавить android:stateListAnimator="@null" к вашему AppBarLayout, как показано ниже.

<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:stateListAnimator="@null"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
person Volodymyr    schedule 02.12.2016
comment
Я использовал как appBarLayout.setElevation(0), так и appBarLayout.setStateListAnimator(null), чтобы отключить возвышение, и appBarLayout.setElevation(10.5), чтобы включить. Он работал во время выполнения и после поворота экрана - person Johnny Five; 11.03.2019

В моем случае мне нужно было изменить высоту AppBarLayout во время выполнения, и setElevation(..) сделал свое дело.

Однако после поворота экрана и вызова setElevation(..) из onCreateOptionMenu ничего не получилось, но setStateListAnimator(null) сделал свое дело.

Поэтому я получил эту логику:

public final float appBarElevation = 10.5f;

public void disableAppBarElevation() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        appBarLayout.setElevation(0);
        appBarLayout.setStateListAnimator(null);
    }
}

public void enableAppBarElevation() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        appBarLayout.setElevation(appBarElevation);
    }
}
person Johnny Five    schedule 11.03.2019