2014-11-07 5 views
0

Есть ли причина, по которой Google решил не использовать способ динамического изменения цвета фона в CardView?Как изменить цвет фона CardView программно

отрезала here enter image description here


РЕШЕНИЕ

Простая строка кода @Justin Пауэлл предложил не работает для меня. На Android 5.0 есть. Но это привело меня в правильном направлении.

Этот код (MyRoundRectDrawableWithShadow быть копией this)

 card.setBackgroundDrawable(new MyRoundRectDrawableWithShadow(context.getResources(), 
       color, 
       card.getRadius(), 
       card.getCardElevation(), 
       card.getMaxCardElevation())); 

... дал мне эту ошибку,

java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.app.MyRoundRectDrawableWithShadow$RoundRectHelper.drawRoundRect(android.graphics.Canvas, android.graphics.RectF, float, android.graphics.Paint)' on a null object reference 
     at com.example.app.MyRoundRectDrawableWithShadow.draw(MyRoundRectDrawableWithShadow.java:172) 

Который просто говорит, что есть интерфейс вызывался, который является нулевым , Затем я проверил CardView source, чтобы узнать, как он это сделал. Я обнаружил, что следующий фрагмент кода инициализирует интерфейс некоторым статическим способом (я действительно не понимаю, почему, пожалуйста, объясните, если вы знаете), который я затем вызываю один раз в классе init, и вы можете затем установить карту цвета с вышеуказанным куском кода.

final RectF sCornerRect = new RectF(); 
MyRoundRectDrawableWithShadow.sRoundRectHelper 
       = new MyRoundRectDrawableWithShadow.RoundRectHelper() { 
      @Override 
      public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, 
             Paint paint) { 
       final float twoRadius = cornerRadius * 2; 
       final float innerWidth = bounds.width() - twoRadius; 
       final float innerHeight = bounds.height() - twoRadius; 
       sCornerRect.set(bounds.left, bounds.top, 
         bounds.left + cornerRadius * 2, bounds.top + cornerRadius * 2); 
       canvas.drawArc(sCornerRect, 180, 90, true, paint); 
       sCornerRect.offset(innerWidth, 0); 
       canvas.drawArc(sCornerRect, 270, 90, true, paint); 
       sCornerRect.offset(0, innerHeight); 
       canvas.drawArc(sCornerRect, 0, 90, true, paint); 
       sCornerRect.offset(-innerWidth, 0); 
       canvas.drawArc(sCornerRect, 90, 90, true, paint); 
       //draw top and bottom pieces 
       canvas.drawRect(bounds.left + cornerRadius, bounds.top, 
         bounds.right - cornerRadius, bounds.top + cornerRadius, 
         paint); 
       canvas.drawRect(bounds.left + cornerRadius, 
         bounds.bottom - cornerRadius, bounds.right - cornerRadius, 
         bounds.bottom, paint); 
       //center 
       canvas.drawRect(bounds.left, bounds.top + cornerRadius, 
         bounds.right, bounds.bottom - cornerRadius, paint); 
      } 
     }; 

Это решение, однако, порождает новую проблему. Не уверен, что происходит с pre-lollipop, но когда CardView сначала инициализируется, он создает RoundRectDrawable в качестве фона из атрибутов, установленных в XML. Когда мы затем меняем цвет с указанным выше кодом, мы устанавливаем MyRoundRectDrawableWithShadow в качестве фона, и если вы хотите снова изменить цвет еще раз, card.getRadius(), card.getCardElevation() и т. Д. Больше не будет работать.

Это поэтому сначала пытается проанализировать фон, который он получает от CardView, как MyRoundRectDrawableWithShadow, из которого он получает значения, если он преуспеет (что будет вторым + временем, когда вы измените цвет). Но если он не сработает (это будет при первом изменении цвета, потому что фон - это другой класс), он получит значения непосредственно из самого CardView.

float cardRadius; 
    float maxCardElevation; 

    try{ 
     MyRoundRectDrawableWithShadow background = (MyRoundRectDrawableWithShadow)card.getBackground(); 
     cardRadius = background.getCornerRadius(); 
     maxCardElevation = background.getMaxShadowSize(); 
    }catch (ClassCastException classCastExeption){ 
     cardRadius = card.getRadius(); 
     maxCardElevation = card.getMaxCardElevation(); 
    } 

    card.setBackgroundDrawable(
      new MyRoundRectDrawableWithShadow(context.getResources(), 
        Color.parseColor(note.getColor()), 
        cardRadius, 
        card.getCardElevation(), 
        maxCardElevation)); 

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

+0

Не редактируйте свой вопрос с помощью своего решения. Добавьте к нему новый ответ. –

ответ

4

Я не знаю каких-либо конкретных рассуждений.

Однако, если вы заинтересованы в взломе вокруг этого упущения ...

Все CardView делает с этим атрибутом является создать скругленный прямоугольник рисует, используя цвет, а затем присваивает его в качестве фона из CardView. Если вы действительно хотите, чтобы установить цвет в программе, вы можете создать копию RoundRectDrawableWithShadow, а затем сделать это:

mCardView.setBackgroundDrawable(new MyRoundRectDrawableWithShadow(getResources(), color, radius)); 

Вы не можете создать подкласс RoundRectDrawableWithShadow или использовать его непосредственно, поскольку она не является общедоступной.

+0

-1 Я не думаю, что это отвечает на вопрос. –

+1

Это казалось более полезным, чем закрытие, в первую очередь основанное на мнениях. –

+0

Подкласс не требуется. Просто сделайте cardview.setBackgroundDrawable (новый RoundRectDrawableWithShadow (context.getResources(), backgroundColor, radius); –

2

Это сложно. Вам необходимо взломать API, чтобы выполнить эту функцию.@Justin Powell's answer прав, но сбой в API 21. Мое решение разрешает это. Вам нужно добавить эти два класса:

MyRoundRectDrawableWithShadow:

package android.support.v7.widget; 

import android.content.res.Resources; 

public class MyRoundRectDrawableWithShadow extends RoundRectDrawableWithShadow { 

    public MyRoundRectDrawableWithShadow(Resources resources, int backgroundColor) { 
    super(resources, backgroundColor, 
     resources.getDimensionPixelSize(R.dimen.cardview_default_radius), 
     resources.getDimensionPixelSize(R.dimen.cardview_default_elevation), 
     resources.getDimensionPixelSize(R.dimen.cardview_default_elevation)); 
    } 

    public MyRoundRectDrawableWithShadow(Resources resources, int backgroundColor, float radius) { 
    super(resources, backgroundColor, radius, 
     resources.getDimensionPixelSize(R.dimen.cardview_default_elevation), 
     resources.getDimensionPixelSize(R.dimen.cardview_default_elevation)); 
    } 

    public MyRoundRectDrawableWithShadow(Resources resources, int backgroundColor, float radius, 
             float shadowSize, float maxShadowSize) { 
    super(resources, backgroundColor, radius, shadowSize, maxShadowSize); 
    } 
} 

MyRoundRectDrawable:

package android.support.v7.widget; 

import android.content.res.Resources; 

public class MyRoundRectDrawable extends RoundRectDrawable { 

    public MyRoundRectDrawable(Resources resources, int backgroundColor) { 
    super(backgroundColor, resources.getDimensionPixelSize(R.dimen.cardview_default_radius)); 
    } 

    public MyRoundRectDrawable(int backgroundColor, float radius) { 
    super(backgroundColor, radius); 
    } 
} 

И затем использовать этот код, чтобы изменить цвет фона:

final Drawable background; 
if (Build.VERSION.SDK_INT >= 21) { 
    background = new MyRoundRectDrawable(color); 
} else { 
    background = new MyRoundRectDrawableWithShadow(resources, color); 
} 
// This is to avoid to use a deprecated method 
if (Build.VERSION.SDK_INT >= 16) { 
    cardView.setBackground(background); 
} else { 
    cardView.setBackgroundDrawable(background); 
} 
16

Просто обновление: Последняя библиотека поддержки обеспечивает прямую функция:

CardView cardView; 
cardView.setCardBackgroundColor(color); 
+0

Спасательная жизнь! Я использовал 'setBackgroundColor', но он удалял мои« cornerRadius »и paddings между CardViews. Теперь он работает так, как ожидалось. – dialex

Смежные вопросы