Установка высоты CardView программно

Я не знаю, является ли этот подход лучшим, но у меня есть следующая проблема:

Я хочу, чтобы элемент списка (CardView) в RecyclerView анимировался при нажатии кнопки, чтобы эта кнопка, некоторые другие представления внутри этого элемента и фон CardView менялись.

Я ловлю animateChange из пользовательского RecyclerView.ItemAnimator: (до сих пор анимация - это просто затухание, определенное в xml через animateLayoutChanges)

public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder, @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
    Log.d("Animation", "Test");
    final MyAdapter.MyViewHolder viewHolder = (MyAdapter.MyViewHolder) newHolder;

    viewHolder.mButtons.setVisibility(View.GONE);
    viewHolder.mHints.setVisibility(View.GONE);
    viewHolder.mImageView.setVisibility(View.GONE);

    ViewGroup.LayoutParams layoutParams = viewHolder.containerCardView.getLayoutParams();
    layoutParams.height = 192;
    viewHolder.containerCardView.setLayoutParams(layoutParams);
    viewHolder.containerCardView.setBackgroundResource(R.drawable.some_background);
    viewHolder.containerCardView.setElevation(20f);

    return true;
}

Как видите, я устанавливаю фон вручную в файле animateChange. Все работает нормально (или, по крайней мере, так, как ожидалось), за исключением повышения уровня CardView. Я попытался установить высоту вручную, но высота не отображается.

РЕДАКТИРОВАТЬ______

В моем CardView есть ImageView и кнопка внутри него. При нажатии на кнопку сама кнопка и картинка должны исчезать, а справа от cardView должна быть красная полоса. Я попытался добиться этого, установив фон (с setBackgroundResource) следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
           android:shape="rectangle">
        <gradient
            android:angle="180"
            android:centerColor="@android:color/transparent"
            android:centerX="0.1"
            android:startColor="@android:color/holo_red_dark"/>
        <corners
            android:bottomLeftRadius="2dip"
            android:bottomRightRadius="2dip"
            android:topLeftRadius="2dip"
            android:topRightRadius="2dip"/>
    </shape>
</item>

<item android:right="4dp">
    <shape android:shape="rectangle">
        <solid android:color="@android:color/white" />
    </shape>
</item>
</layer-list>

Это всего лишь XML-файл с красной линией справа. Есть ли у вас какие-либо предложения по другому способу приблизиться к моей цели?


person Vancore    schedule 22.02.2017    source источник
comment
I tried to set the elevation by hand, but there is no elevation shown Что ты имеешь в виду?   -  person ATEF    schedule 22.02.2017
comment
viewHolder.containerCardView.setElevation(20f); CardView имеет высоту до, но не после того, как я установил новый фон. Поэтому я попытался установить его снова с помощью этой строки кода.   -  person Vancore    schedule 22.02.2017
comment
Почему бы вам просто не установить его в XML?   -  person ATEF    schedule 22.02.2017
comment
CardView имеет высоту в XML, но не имеет ее после установки фона.   -  person Vancore    schedule 22.02.2017
comment
@Vancore, именно по этой причине вы не видите тени.   -  person Massimo    schedule 22.02.2017
comment
Да я так и предполагал. Может тогда мой подход не правильный. Я обновлю свой вопрос.   -  person Vancore    schedule 22.02.2017


Ответы (3)


Вы должны вызывать setCardElevation, а не setElevation. Второй модифицирует свойство elevation, которое все View подклассы есть со времен Lollipop (уровень API 21).

И НЕ ИСПОЛЬЗУЙТЕ setBackgroundResource: фон карты — это ее высота (поскольку карта совместима со всеми версиями Android до Lollipop, в которых нет свойства elevation). Используйте setCardBackgroundColor, чтобы установить цвет фона (или app:cardBackgroundColor в вашем xml).

Если вам нужно фоновое изображение, а не цвет, поместите ImageView внутри своей карты, как предлагает этот ответ.

Делайте, что хотите, но НЕ вызывайте никаких методов setBackground... для CardView, иначе вы потеряете тень карты (ее эффект возвышения).

Во-вторых, для анимации высоты используйте следующий код:

ObjectAnimator animator = ObjectAnimator.ofFloat(cardView, "cardElevation", start, end);
// if needed set duration, interpolator, or what you want on the animator
animator.start();
person Massimo    schedule 22.02.2017
comment
Ваша карта содержится внутри другого макета? Тень возвышения может быть просто не видна из-за свойств clipChildren и clipToPadding компоновки контейнера (по умолчанию true). - person Massimo; 22.02.2017
comment
Я обновил ответ. В вашем коде есть проблема, связанная с неправильным использованием методов View. - person Massimo; 22.02.2017
comment
Мой cardView действительно был внутри RelativeLayout. Я удалил родительский RelativeLayout, так как мой cardView является элементом строки recyclerView, но до сих пор никаких изменений. Проблема в том, что я не могу просто использовать backgroundColor, потому что я хочу иметь определенный фон (только с красной линией справа) - person Vancore; 22.02.2017
comment
CardView является расширением FrameLayout: поэтому поместите ImageView в качестве первого сына карты и поместите свой фон как src этого ImageView (в конечном итоге с правым scaleType). stackoverflow.com/a/33920684/1507512 - person Massimo; 22.02.2017
comment
Я обновил ответ, чтобы объяснить, как правильно анимировать возвышение при нажатии на карточку. - person Massimo; 22.02.2017
comment
Кажется, что подход с ImageView в качестве первого дочернего элемента работает, хотя у меня есть некоторые проблемы с layoutGravity (но это, вероятно, другая проблема) - person Vancore; 22.02.2017

попробуй использовать

cardview.setMaxCardElevation();

но обратите внимание, что:

Вызов этого метода не имеет никакого эффекта, если версия ОС устройства — Lollipop или новее, а getUseCompatPadding() имеет значение false.

Или попробуйте

cardview.setCardElevation();

Источник

Или из XML:

Добавьте android:clipChildren="false" к родительскому элементу вашей карты или добавьте небольшое количество отступов к вашему представлению и установите android:clipToPadding="false"

и использовать

card_view:cardElevation="VALUE"
person ATEF    schedule 22.02.2017
comment
clipTopadding и clipChildren, похоже, не влияют на это. Я думаю проблема кроется в другом. - person Vancore; 22.02.2017
comment
@Vancore, к сожалению, у меня нет идей! - person ATEF; 22.02.2017

Outline представления — это то, что "управляет формой его теней". Когда изменение фона неявно изменяет структуру представления, вы должны явно аннулировать структуру, вызвав View.invalidateOutline(), чтобы тени вокруг вида перерисовывались.

person Gabriel Feo    schedule 19.10.2019
comment
Добро пожаловать в СО! Пожалуйста, попробуйте немного объяснить свой ответ. Ответы с несколькими словами и некоторыми ссылками должны быть добавлены как комментарии, а не как ответы. - person David García Bodego; 19.10.2019