Прикрепите пользовательский стиль 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>
Update
Аналогичный вопрос здесь без ответа.
Ответы
Ответ 1
В 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, чтобы использовать новый атрибут, вы будете использовать его следующим образом
style="?attr/cardStyle"
Ответ 2
Чтобы узнать больше о том, как реализовать решение 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>
Затем используйте attr, где у вас есть CardView:
<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>
Ответ 3
Если вы не хотите добавлять style="?cardViewStyle"
к каждому CardView
в своих макетах, вы можете подклассифицировать CardView
и установить атрибут стиля в конструкторе (слишком плохо, что они не делали этого в библиотеке поддержки). Затем используйте этот подкласс в XML, а не CardView
.
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>
* <attr format="reference" name="cardViewStyle"/>
* </pre>
* <p>
* You'll need to set that attribute in your theme, as usual:
* <pre>
* <item name="cardViewStyle">@style/CardView.MyStyle</item>
* </pre>
* And define the style itself, for example:
* <pre>
* <style name="CardView.MyStyle" parent="CardView.Light">
* <item name="cardCornerRadius">0dp</item>
* </style>
* </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>
Ответ 4
Единственное решение, которое я смог придумать, - это вручную удерживать постоянную переменную для цвета карты, после каждой темы изменения. Затем я получаю каждый экземпляр карты, которая находится в моем приложении, и устанавливает ее цвет этой постоянной переменной.
Итак, у меня есть 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);
}
}
Это определенно не лучший способ сделать это, но пока кто-то еще не найдет лучший способ реализовать стиль, это все, о чем я могу думать.