Изменение цвета тени CardView
Этот вопрос задавали ВО много раз, но все же я не нашел хорошего решения этой проблемы.
Зачем мне это нужно? Хорошо, потому что проект меня и моей команды разрабатывает, имеет стиль iOS.
Что я пробовал?
- 9.pathch shadow generator, но 9.pathes - это, по существу, png, и это не дает мне никакой гибкости, и если я буду использовать этот подход, я должен редактировать поля везде.
- Углеродная библиотека поддерживает пользовательские тени, и их рисуют вне границ вида, но есть проблема с закругленными прямоугольниками, когда библиотека не рисует тени для закругленных углов.
- используя старую реализацию CardView и переориентируя свой теневой цвет, но она нарисована внутри границ карты, поэтому это не вариант.
Итак, есть ли способ изменить теневой цвет CardView с минимальными изменениями всех файлов макета и с теневой тенью вне представления, как это делает оригинальный CardView?
Ответы
Ответ 1
Рассмотрите эту ветку в твиттере, где Ник Батчер рассказывает о том, как реализовать эту функцию:
Подробности смотрите в атрибутах outlineAmbientShadowColor
, outlineSpotShadowColor
, spotShadowAlpha
и ambientShadowAlpha
. К сожалению, это возможно начиная с API 28 и далее.
Для более низких API Ник поделился суть. Вот результат:
Running on API 21
Этот метод не связан напрямую с CardView
, его можно применить к любому View
.
Ответ 2
Вы можете реализовать это без наличия карты, а также иметь все свойства карты
Ты должен сделать:
-
Скопируйте два класса
-
Оберните требуемое представление с помощью пользовательского представления, как в примере, вам не нужно вносить изменения в свой макет или где-либо еще!
В нижеприведенном классе создается пользовательский вид, который будет обертывать ваш макет/вид, который будет отображаться в кард-визите, с пользовательским цветом тени
Создайте класс:
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.LinearLayout;
import com.qzion.nfscrew.R;
public class RoundLinerLayoutNormal extends LinearLayout {
public RoundLinerLayoutNormal(Context context) {
super(context);
initBackground();
}
public RoundLinerLayoutNormal(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initBackground();
}
public RoundLinerLayoutNormal(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initBackground();
}
private void initBackground() {
setBackground(ViewUtils.generateBackgroundWithShadow(this,R.color.white,
R.dimen.radius_corner,R.color.colorPrimaryDark,R.dimen.elevation, Gravity.BOTTOM));
}
}
Также создайте класс для настроек тени, ViewUtils.java
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.v4.content.ContextCompat;
import android.view.Gravity;
import android.view.View;
import static android.support.v4.view.ViewCompat.LAYER_TYPE_SOFTWARE;
public class ViewUtils {
public static Drawable generateBackgroundWithShadow(View view, @ColorRes int backgroundColor,
@DimenRes int cornerRadius,
@ColorRes int shadowColor,
@DimenRes int elevation,
int shadowGravity) {
float cornerRadiusValue = view.getContext().getResources().getDimension(cornerRadius);
int elevationValue = (int) view.getContext().getResources().getDimension(elevation);
int shadowColorValue = ContextCompat.getColor(view.getContext(),shadowColor);
int backgroundColorValue = ContextCompat.getColor(view.getContext(),backgroundColor);
float[] outerRadius = {cornerRadiusValue, cornerRadiusValue, cornerRadiusValue,
cornerRadiusValue, cornerRadiusValue, cornerRadiusValue, cornerRadiusValue,
cornerRadiusValue};
Paint backgroundPaint = new Paint();
backgroundPaint.setStyle(Paint.Style.FILL);
backgroundPaint.setShadowLayer(cornerRadiusValue, 0, 0, 0);
Rect shapeDrawablePadding = new Rect();
shapeDrawablePadding.left = elevationValue;
shapeDrawablePadding.right = elevationValue;
int DY;
switch (shadowGravity) {
case Gravity.CENTER:
shapeDrawablePadding.top = elevationValue;
shapeDrawablePadding.bottom = elevationValue;
DY = 0;
break;
case Gravity.TOP:
shapeDrawablePadding.top = elevationValue*2;
shapeDrawablePadding.bottom = elevationValue;
DY = -1*elevationValue/3;
break;
default:
case Gravity.BOTTOM:
shapeDrawablePadding.top = elevationValue;
shapeDrawablePadding.bottom = elevationValue*2;
DY = elevationValue/3;
break;
}
ShapeDrawable shapeDrawable = new ShapeDrawable();
shapeDrawable.setPadding(shapeDrawablePadding);
shapeDrawable.getPaint().setColor(backgroundColorValue);
shapeDrawable.getPaint().setShadowLayer(cornerRadiusValue/3, 0, DY, shadowColorValue);
view.setLayerType(LAYER_TYPE_SOFTWARE, shapeDrawable.getPaint());
shapeDrawable.setShape(new RoundRectShape(outerRadius, null, null));
LayerDrawable drawable = new LayerDrawable(new Drawable[]{shapeDrawable});
drawable.setLayerInset(0, elevationValue, elevationValue*2, elevationValue, elevationValue*2);
return drawable;
}
}
и, наконец, ваш XML, где у вас есть представления, требующие наличия тени.
<com.qzion.nfscrew.utils.RoundLinerLayoutNormal
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This view will have shadow"/>
</com.qzion.nfscrew.utils.RoundLinerLayoutNormal>
Ответ 3
Я думаю о простом решении без использования Java или некоторых библиотек. Вы должны сделать Drawable shape и поместить его в папку с возможностью drawable
а затем настроить градиент как тень.
Например, в моем решении я добавил два цвета:
<color name="yellow_middle">#ffee58</color>
<color name="yellow_end">#7ae7de83</color>
Затем я сделал файл и поместил его в папку с возможностью drawable\card_view_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="10dp"
android:height="10dp" />
<corners android:radius="6dp" />
<stroke
android:width="2dp"
android:color="@color/yellow_end" />
<gradient
android:angle="-90"
android:centerColor="@color/yellow_middle"
android:endColor="@color/yellow_end"
android:startColor="#fff" />
</shape>
Затем оттуда вам нужно обернуть свой вид (который был бы внутри CardView) в контейнере, LinearLayout
как LinearLayout
затем применить в качестве фона к контейнеру, который вы хотите видеть как вид карты. Чтобы решить эту проблему, добавьте немного заполнения (Thats your shadow) самому контейнеру. Например, проверьте мой:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.xenolion.ritetrends.MainActivity">
<LinearLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:background="@drawable/card_view_shape"
android:orientation="vertical"
android:paddingBottom="10dp"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:paddingTop="3dp">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:gravity="center"
android:text="I love StackOverflow"
android:textColor="#000"
android:textSize="18sp" />
</LinearLayout>
</FrameLayout>
Затем результаты выглядят так:
Регулировка нижнего отступов будет выглядеть так:
КОММЕНТАРИЙ
Поскольку я не художник, но если вы играете с ним, вы можете заставить все это выглядеть так же, как CardView
проверить некоторые подсказки:
- Помещение нескольких градиентов в форму
- Отрегулируйте конечные цвета градиентов, чтобы они выглядели более сероватыми
- Конечные цвета также должны быть немного прозрачными
- Отрегулируйте видимость вида, чтобы выглядеть как тень и цветной, но сероватый
- Основной фон "Вид" также имеет значение для приведения реальности. Оттуда редизайн формы выглядит еще более реалистично, как
CardView
.