【问题标题】:How to change background color of CardView programmatically如何以编程方式更改 CardView 的背景颜色
【发布时间】:2014-11-07 18:14:18
【问题描述】:

Google 决定不制定动态更改 CardView 的背景颜色的方法是否有原因?

截断here


解决方法

@Justin Powell 建议的简单代码行对我不起作用。在 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);
            }
        };

然而,这个解决方案确实产生了一个新问题。不确定在棒棒糖前会发生什么,但是当 CardView 首次初始化时,它似乎从您在 XML 中设置的属性创建一个 RoundRectDrawable 作为背景。当我们用上面的代码改变颜色时,我们设置一个 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));

希望这是有道理的,我不是以英语为母语的人...如前所述,这仅在 Lollipop 上进行了测试。

【问题讨论】:

  • 不要用您的解决方案编辑您的问题。用它添加一个新答案。

标签: android android-5.0-lollipop android-cardview


【解决方案1】:

只是为了更新: 最新的支持库提供了直接函数:

CardView cardView;
cardView.setCardBackgroundColor(color);

【讨论】:

  • 救命!我正在使用setBackgroundColor,但它正在删除我的cornerRadius 和 CardViews 之间的填充。现在它按预期工作。
【解决方案2】:

我不知道有什么特别的原因。

但是,如果您有兴趣解决这个遗漏...

CardView 对这个属性所做的所有事情就是使用颜色创建一个圆角矩形drawable,然后将其指定为 CardView 的背景。如果您真的想以编程方式设置颜色,可以创建RoundRectDrawableWithShadow 的副本,然后执行以下操作:

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

您不能继承 RoundRectDrawableWithShadow 或直接使用它,因为它不是公共的。

【讨论】:

  • 这似乎比关闭主要基于意见更有帮助。
  • 不需要子类化。只需做 cardview.setBackgroundDrawable(new RoundRectDrawableWithShadow(context.getResources(), backgroundColor, radius);
  • 这个问题当然可以是基于意见的,但是这个问题有可能实际上有一个真实的而不是基于意见的答案。
  • 好吧,感谢您监督我的回答。也许更好地利用您的时间是发布您自己的答案..?
  • 我会接受你的回答,尽管你不知道原因,也没有给我一个可行的解决方案。但是,您确实为我指明了正确的方向,而且我现在可以正常工作了,所以谢谢您。
【解决方案3】:

这很棘手。您需要破解 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);
}

【讨论】:

    【解决方案4】:

    只需写下这个 sn-p: cardView.setCardBackgroundColor(getResources().getColor(R.color.colorPrimary)); 你想要代码的地方

    【讨论】:

      猜你喜欢
      • 2014-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-28
      • 1970-01-01
      相关资源
      最近更新 更多