将自定义CardView样式附加到主题

时间:2015-05-23 21:37:20

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

在我的应用中,我有两个主题(浅色和深色),我希望我的所有CardView都根据所选的主题更改背景颜色。

想要的是:

<android.support.v7.widget.CardView
    style="@style/CardView.MyBlue"
    android:layout_width="200dp"
    android:layout_height="100dp"
    android:layout_gravity="center_horizontal">

以上代码不是动态的。我需要根据是否选择了浅色或深色主题自动应用我的两种样式。

我现在所做的不起作用:

<style name="AppTheme.Light" parent="Theme.AppCompat.Light">
   ...
   <item name="cardViewStyle">@style/CardViewStyle.Light</item>
</style>
<style name="AppTheme.Dark" parent="Theme.AppCompat">
   ...
   <item name="cardViewStyle">@style/CardViewStyle.Dark</item>
</style>

<style name="CardViewStyle.Light" parent="CardView">
    <item name="cardBackgroundColor">@color/cardview_dark_background</item>
</style>

<style name="CardViewStyle.Dark" parent="CardView">
        <item name="cardBackgroundColor">@color/cardview_light_background</item>
</style>

我在某处读到你可以在styleable.xml中定义一个/res/values/文件来键入单词cardViewStyle,所以我这样做了:

styleable.xml:

<resources>
    <declare-styleable name="AppTheme">
        <attr name="cardViewStyle" format="reference" />
    </declare-styleable>
</resources>

更新

类似的问题here也没有答案。

4 个答案:

答案 0 :(得分:19)

在styles.xml中

<resources>

    <attr format="reference" name="cardStyle"/>

    <style name="Light" parent="Theme.AppCompat.NoActionBar">
        <item name="cardStyle">@style/CardView.Light</item>
        ...
    </style>

    <style name="Dark" parent="Theme.AppCompat.NoActionBar">
        <item name="cardStyle">@style/CardView.Dark</item>
        ...
    </style>
</resources>

然后在你的其他xml中使用new属性,你会像这样使用它

style="?attr/cardStyle"

答案 1 :(得分:8)

显示有关如何实施David Park解决方案的更多详细信息......

将它放在attrs.xml中:

<declare-styleable name = "cardStyle">
     <attr name="cardStyle" format="reference" />
</declare-styleable>

<style name="Light" parent="Theme.AppCompat.NoActionBar">
    <item name="cardStyle">@style/CardView.Light</item>
</style>

<style name="Dark" parent="Theme.AppCompat.NoActionBar">
    <item name="cardStyle">@style/CardView.Dark</item>
</style>

然后,将cardStyle添加到styles.xml中的主题:

<style name="AppThemeLight" parent="AppTheme.Base"/>
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="cardStyle">@style/CardView.Light</item>
</style>

<style name="AppThemeDark" parent="AppTheme.Base.Dark"/>
<style name="AppTheme.Base.Dark" parent="Theme.AppCompat.NoActionBar">
    <item name="cardStyle">@style/CardView.Dark</item>
</style>

然后在任何有CardView的地方使用attr:

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/header_card"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardCornerRadius="2dp"
    card_view:cardElevation="2dp"
    style="?attr/cardStyle">

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:id="@+id/header_title"

</android.support.v7.widget.CardView>

答案 2 :(得分:1)

如果您不想将CardView添加到布局中的每个CardView,您可以继承CardView并在构造函数中设置style属性(太糟糕了,他们没有在支持库中执行此操作)。然后在XML中使用该子类,而不是package com.example.widget; import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.CardView; import android.util.AttributeSet; import com.example.R; /** * {@link CardView} subclass that allows theme'ing through * the {@link R.attr#cardViewStyle} attribute. * <p> * The attribute needs to be defined, for example in <code>attrs.xml</code> as: * <pre> * &lt;attr format="reference" name="cardViewStyle"/&gt; * </pre> * <p> * You'll need to set that attribute in your theme, as usual: * <pre> * &lt;item name="cardViewStyle"&gt;@style/CardView.MyStyle&lt;/item&gt; * </pre> * And define the style itself, for example: * <pre> * &lt;style name="CardView.MyStyle" parent="CardView.Light"&gt; * &lt;item name="cardCornerRadius"&gt;0dp&lt;/item&gt; * &lt;/style&gt; * </pre> */ public class StylishCardView extends CardView { public StylishCardView(@NonNull Context context) { this(context, null); } public StylishCardView(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, R.attr.cardViewStyle); } public StylishCardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } }

cardViewStyle

需要定义属性attrs.xml,例如在<attr format="reference" name="cardViewStyle"/> 中定义:

<item name="cardViewStyle">@style/CardView.MyStyle</item>

您需要像往常一样在主题中设置该属性:

<style name="CardView.MyStyle" parent="CardView.Light">
    <item name="cardCornerRadius">0dp</item>
</style>

并定义样式本身,例如:

var $errorMsg = $(".errorMsg"),
    $form = $("#form");
// This is the way how you fix it with click on "Search"
$("#search").on("click", function(e) {
        // Check if the value is a number
    var checkNumber = $.isNumeric($("#ref").val());

    // If it is a number show the form empty up the error message
    if (checkNumber) {
        $form.show()
        $('label[for="ref"]').removeClass("errorMsg");
        $errorMsg.empty()
    } else {
        // Which means is not a number so show the error
        $errorMsg.html("Reference number required")
        $('label[for="ref"]').addClass("errorMsg");
        $form.hide()
    }
})

答案 3 :(得分:0)

我能够想出的唯一解决方案是在每次主题更改后手动持有卡片颜色的常量变量。然后,我得到了我的应用程序中的卡的每个实例,并将其颜色设置为该常量变量。

所以,我有一个BaseActivity,我的所有活动都来自于它。在其中,除了处理主题外,我还处理卡片的颜色变化。见下文:

BaseActivity.java

public class BaseActivity extends ActionBarActivity {
    private static final int DEFAULT_THEME_ID = R.style.AppTheme_Dark;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        int theme_id =
                PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getInt("THEME_ID", DEFAULT_THEME_ID);
        setTheme(theme_id);

        int card_color;
        if (theme_id == DEFAULT_THEME_ID){
            card_color = R.color.cv_dark;
        } else{
            card_color = R.color.cv_light;
        }
        Constants.CARD_COLOR = card_color;
        super.onCreate(savedInstanceState);
    }
}

这绝对不是最好的方法,但是在其他人找到更好的方式来实现样式之前,这是我能想到的。