This is for anyone who comes across this and is still just as confused as I was, even after a lot of reading and trial & error. Hopefully this helps.
The folder structure is like @Dmitry stated.
res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppBase" parent="Theme.MaterialComponents.NoActionBar">
<!-- simple: overrides colorPrimary in parent theme -->
<item name="colorPrimary">@color/brand_blue</item>
<item name="colorSecondary">@color/brand_grey</item>
<!-- sets the attributes in materialButtonStyle with style: myMaterialButton -->
<!-- the materialButtonStyle attribute is what actually changes the button settings -->
<item name="materialButtonStyle">@style/myMaterialButton</item>
</style>
<!-- this style consists of common 'attributes' among all API versions -->
<!-- you can choose to add a parent to inherit an additional style -->
<!-- unlike the materialButtonStyle attribute, this parent is not necessary to change the button settings -->
<style name="myMaterialButton" parent="Widget.MaterialComponents.Button">
<item name="cornerRadius">60dp</item>
<item name="android:paddingVertical" tools:targetApi="26">20dp</item>
</style>
<!-- this will add on and override AppBase and should include any changes that differ from other API versions -->
<style name="AppBaseChanges" parent="AppBase">
<!-- to inherit myMaterialButton, you don't have to include it in here, since it's in AppBase -->
<!-- however, if you want to extend myMaterialButton, create a new style as its child -->
<item name="materialButtonStyle">@style/myMaterialButtonAPI_All</item>
</style>
<!-- make sure the parent is myMaterialButton to inherit/override its settings -->
<!-- this will be picked for all APIs lower than other styles like this -->
<style name="myMaterialButtonAPI_All" parent="myMaterialButton">
<item name="backgroundTint">?attr/colorPrimary</item>
</style>
</resources>
res/values-v2/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- restate the same declaration as the other xml file-->
<style name="AppBaseChanges" parent="AppBase">
<!-- use a different name (...API_2) for the overriding style -->
<item name="materialButtonStyle">@style/myMaterialButtonAPI_2</item>
</style>
<style name="myMaterialButtonAPI_2" parent="myMaterialButton">
<item name="backgroundTint">?attr/colorSecondary</item>
</style>
</resources>
Set the manifest theme to AppBaseChanges
. The app will pick only one AppBaseChanges
style to apply changes, so be sure to carefully override the right styles to ensure you are inheriting from lower level versions.
For some reason, AndroidStudio doesn't do a good job at all previewing themes, so before you think it's not working, relaunch the app to see the changes. There are also situations where I have no idea why it wasn't updating the setting and couldn't find where it was overriding the theme. In those cases you can dig further, or avoid the hassle and just apply the relevant style directly to the view.
Here's the order of precedence for the sample themes described above. The higher the style, the higher precedence it has and will override the lower style.
- either
myMaterialButtonAPI_All
or myMaterialButtonAPI_2
AppBaseChanges
(only one is chosen)
myMaterialButton
Widget.MaterialComponents.Button
AppBase
Theme.MaterialComponents.NoActionBar