getTheme().applyStyle(...) 多次而不覆盖前一个

getTheme().applyStyle(...) multiple times without overwriting the previous one

当我多次向 AppTheme 应用额外属性时,它会覆盖前一个。这是我使用的代码:

主要活动:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {

    getTheme().applyStyle(R.style.AppTheme_OverlayPrimaryRed);

    // If you change `false` to `true`, the overlay above is overwritten.
    if (false) {
        getTheme().applyStyle(R.style.AppTheme_OverlayAccentRed);
    }

    super.onCreate(savedInstanceState);

    ...
}

AppTheme.OverlayPrimaryRed:

<style name="AppTheme.OverlayPrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

AppTheme.OverlayAccentRed:

<style name="AppTheme.OverlayAccentRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

有什么办法可以解决这个问题吗?

编辑 2:这是一次失败的尝试,再次应用样式会删除以前通过编程设置的样式。

Android 中的每个样式都可以有父样式。因此,子样式将继承其父样式并应用自己的样式。此外,子项可以覆盖其父项的样式或属性。

<!-- This is a parent style -->
<style name="AppTheme.OverlayPrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

<!-- This is a child of above style -->
<style name="AppTheme.OverlayAccentRed" parent="AppTheme.OverlayPrimaryRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

在 Android 开发人员资源中阅读 Defining Styles。另外,如果您不想使用 parent 属性:

If you want to inherit from styles that you've defined yourself, you do not have to use the parent attribute. Instead, just prefix the name of the style you want to inherit to the name of your new style, separated by a period. For example, to create a new style that inherits the MyTextStyle style defined, but make the color red, you can author the new style like this:

<style name="MyTextStyle">
    <item name="android:textAllCaps">false</item>
    <item name="android:textColor">#FFFFFF</item>  <!-- white text (default) -->
    <item name="android:textStyle">bold</item>
    <item name="android:textSize">12dp</item>
</style>

<!-- red text -->
<style name="MyTextStyle.RED">
    <item name="android:textColor">#FF0000</item>
</style>

<!-- green text -->
<style name="MyTextStyle.GREEN">
    <item name="android:textColor">#00FF00</item>
</style>

<!-- blue text -->
<style name="MyTextStyle.BLUE">
    <item name="android:textColor">#0000FF</item>
</style>

Notice that there is no parent attribute in the tag, but because the name attribute begins with the MyTextStyle style name (which is a style that you have created), this style inherits all style properties from that style. This style can override the android:textColor property to make the text red. You can reference this new style as @style/MyTextStyle.RED.

You can continue inheriting like this as many times as you'd like, by chaining names with periods. For example, you can extend MyTextStyle.RED to be bigger, with:

<style name="MyTextStyle.RED.Big">
    <item name="android:textSize">30sp</item>
</style>

编辑 1:

<!-- this is your root style -->
<style name="AppTheme.Overlay">
    <!-- default styles for primary, primaryDark (you can add accent too) -->
</style>

<!-- 1. add Custom Primary Color to root style -->
<style name="AppTheme.Overlay.PrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

<!-- 1. add Custom Accent Color to root style -->    
<style name="AppTheme.Overlay.AccentRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

<!-- 2. add Custom Primary Color to root style -->
<style name="AppTheme.Overlay.PrimaryBlue">
    <item name="colorPrimary">@color/material_blue_500</item>
    <item name="colorPrimaryDark">@color/material_blue_700</item>
</style>

<!-- 2. add Custom Accent Color to root style -->    
<style name="AppTheme.Overlay.AccentBlue">
    <item name="colorAccent">@color/material_blue_A200</item>
</style>

<!-- add 10 for each...... -->

为您的原色制作 10 种样式,为您的强调色制作 10 种样式。

然后,在您的代码中:

// if root style has some styles to add (default)
getTheme().applyStyle(R.style.AppTheme_Overlay);

// first color selection
getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryRed);
getTheme().applyStyle(R.style.AppTheme_Overlay_AccentRed);

// when you want blue color
getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryBlue);
getTheme().applyStyle(R.style.AppTheme_Overlay_AccentBlue);

// when you want bluePrimary, but redAccent color (bad choice)
getTheme().applyStyle(R.style.AppTheme_Overlay_PrimaryBlue);
getTheme().applyStyle(R.style.AppTheme_Overlay_AccentRed);

此处,AppTheme_Overlay_PrimaryBlue 将覆盖 AppTheme_Overlay_PrimaryRed。等等。

您刚刚添加了一种根样式、十种原色样式和十种强调色样式 = 21 种样式。

您的样式定义 AppTheme.OverlayPrimaryRedAppTheme.OverlayAccentRed 隐式继承自 AppTheme。由于 AppTheme 可能还包含 colorPrimarycolorPrimaryDark 的定义,第二个 applyStyle 语句也将设置这些属性,撤消第一个 applyStyle 调用。

因此,我在回答 this question 时没有在样式覆盖名称中使用任何点。

如果出于美观原因想要保留点,您可以像这样为叠加层定义一个空的父级样式:

<style name="Overlay">
</style>

<style name="Overlay.PrimaryRed">
    <item name="colorPrimary">@color/material_red_500</item>
    <item name="colorPrimaryDark">@color/material_red_700</item>
</style>

<style name="Overlay.AccentRed">
    <item name="colorAccent">@color/material_red_A200</item>
</style>

已应用样式

textInputStyle = R.style.TextInputFilled;
recreate();

在 activity 销毁之前保存样式:

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("textInputStyle", textInputStyle);
}

在 activity 创建时应用样式:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        textInputStyle = savedInstanceState.getInt("textInputStyle", 
        R.style.TextInputFilled);
    }
    getTheme().applyStyle(textInputStyle, true);
    setContentView(R.layout.act_text_field);
}