Изменение цвета тени CardView - PullRequest
0 голосов
/ 23 июня 2018

Этот вопрос задавался SO так много раз, но все же я не нашел хорошего решения этой проблемы.

Зачем мне это нужно делать? Хорошо, потому что проект, который я и моя команда разрабатываем, имеет стиль iOS.

Что я пробовал?

  1. генератор тени 9.pathch но 9.pathes по сути являются pngs, и это не дает мне гибкости, и если я буду использовать этот подход, я должен везде редактировать поля.
  2. Библиотека углерода поддерживает пользовательские тени, и они рисуются вне границ вида, но есть проблема в отношении скругленных прямоугольников, когда библиотека не рисует тени для закругленных углов.
  3. используя старую реализацию CardView и переопределяя ее цвет тени, но он рисуется внутри границ карты, поэтому это не вариант.

Так есть ли способ изменить цвет тени в CardView с минимальным редактированием всех файлов макета и с отрисовкой тени вне вида, как это делает оригинальный CardView?

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Рассмотрим эту тему в твиттере, где Ник Батчер рассказывает о том, как реализовать эту функцию:

enter image description here

image

См. Атрибуты outlineAmbientShadowColor, outlineSpotShadowColor, spotShadowAlpha и ambientShadowAlpha.К сожалению, это возможно начиная с API 28.

Для более низких API Ник поделился gist .Вот результат:

image

Запуск по API 21

Этот метод нене подключен напрямую к CardView, может применяться к любому View.

0 голосов
/ 04 июля 2018

Ну, я думаю о простом решении без использования 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, затем применить его в качестве фона для контейнера, который вы хотите видеть как cardview. Чтобы решить эту проблему, добавьте отступ (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>

Тогда результаты выглядят так:
Testing Results

Настройка нижнего отступа будет выглядеть так:

Testing results

COMMENT
Так как я не художник, но если вы играете с ним, вы можете сделать все это в точности как CardView проверьте некоторые подсказки:

  • Помещение нескольких градиентов в форму
  • Отрегулируйте конечные цвета градиентов, чтобы они выглядели более серыми
  • Конечные цвета также должны быть немного прозрачными
  • Настройте отступы вашего вида так, чтобы они выглядели как тени и были цветными, но серыми
  • Фон основного вида также важен для воплощения реальности Оттуда измените форму, чтобы она выглядела еще более реалистично, как CardView.
0 голосов
/ 23 июня 2018

Вы можете реализовать это без просмотра карты, а также можете иметь все свойства cardview

Вы должны сделать:

  1. Скопируйте два класса

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

Также создайте класс для Shadow Settings, 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>
...