2

When I apply extra attributes to the AppTheme multiple times it overwrites the previous one. This is the code I am using:

MainActivity:

@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>

Any ideas how I can solve this issue?

Thomas Vos
  • 12,271
  • 5
  • 33
  • 71

3 Answers3

6

Your style definitions AppTheme.OverlayPrimaryRed and AppTheme.OverlayAccentRed implicitly inherit from AppTheme. Since AppTheme probably also contains a definition for colorPrimary and colorPrimaryDark the second applyStyle statement will set these attributes as well, undoing the first applyStyle call.

For this reason I did not use any dots in the style overlay names in my answer to this question.

If you want to keep the dots for esthetical reasons you can define an empty parent style for overlays like so:

<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>
Community
  • 1
  • 1
devconsole
  • 7,875
  • 1
  • 34
  • 42
  • Amazing, had no idea this implicit extension of themes existed. This solved my problem of flags disappearing when using applyStyle, such as android:windowDrawsSystemBarBackgrounds, android:statusBarColor etc. – 0101100101 Jun 17 '20 at 07:47
  • Was banging my head against the wall all day until I found this. Thank you! – VIN Jun 15 '21 at 21:08
1

Edit 2: This is a failed attempt, applying styles again removes previous styles set through programming.

Every style in Android can have parent styles. So, the child style will inherit styles of its parent and apply its own styles too. Also, a child can override its parent's styles or properties.

<!-- 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>

Read Defining Styles at Android Developer's Resource. Also, if you don't want to use parent attribute :

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>

Edit 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...... -->

Make 10 styles for your Primary Color, and 10 styles for your Accent Color.

Then, in your code:

// 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);

Here, AppTheme_Overlay_PrimaryBlue will override AppTheme_Overlay_PrimaryRed. And, so on.

You just added one root style, ten primary color styles and ten accent color styles = 21 styles.

rupinderjeet
  • 2,984
  • 30
  • 54
  • Thank you for your detailed answer. In my app I want an option to change the "primary(dark) color" and "accent color". For 10 colors this is: 10 + 10 = 20 possible overlay themes. Your method has 10 * 10 = 100 possible overlay themes. This is a lot to put in styles.xml. Do you understand this or do you want me to explain in more detail? – Thomas Vos Jan 21 '17 at 14:44
  • I just learned this before replying to you. Please check my edit. If it still doesn't answer your question, [let us continue our discussion in this room](http://chat.stackoverflow.com/rooms/133704/), tell me where am I missing? – rupinderjeet Jan 21 '17 at 15:12
0

a style is applied

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

save style before activity destroyed:

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

apply style when activity is creating:

@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);
}
wslaimin
  • 49
  • 2