Search code examples
javaandroidandroid-theme

Dynamically retrieve custom styles declared into "styles.xml"


In Android Studio I've declared some custom styles with some custom attributes, like the following two:

<resources>

<!-- Base application theme. -->
<style name="AppThemeBlueDark" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/AppThemeBlueDarkColorPrimary</item>
    <item name="colorPrimaryDark">@color/AppThemeBlueDarkColorPrimaryDark</item>
    <item name="colorAccent">@color/AppThemeBlueDarkColorAccent</item>
    <item name="android:colorBackground">@color/AppThemeBlueDarkBackground</item>

    <item name="my_type">my_theme</item>
    <item name="my_id">0</item>
    <item name="my_name">Dark Blue</item>
    <item name="my_default">true</item>
</style>

<style name="AppThemeBlueLight" parent="@style/Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/AppThemeBlueLightColorPrimary</item>
    <item name="colorPrimaryDark">@color/AppThemeBlueLightColorPrimaryDark</item>
    <item name="colorAccent">@color/AppThemeBlueLightColorAccent</item>
    <item name="android:colorBackground">@color/AppThemeBlueLightBackground</item>

    <item name="my_type">my_theme</item>
    <item name="my_id">1</item>
    <item name="my_name">Light Blue</item>
    <item name="my_default">false</item>
</style>

</resources>

Now I want to create a java custom Class that is able to retrieve all my defined styles without a previous knowledge about how many they are and their names; something like:

public class ThemeChanger {

// Populate myThemes
public void ThemeChanger() {
    TypedArray theme_res = R.style.getStyleNames();
}
}

}

Obviously, the method "getStyleNames()" is pure fantasy!

Is this feasible in some way?

The final goal is to create a generic reusable class that will be able to manage and change app's themes, simply defining the themes into the standard "styles.xml" but with these custom attributes, without the necessity to modify the class if I will decide to use different themes/names.

Thanks very much for any help.


Solution

  • I found a solution (perhaps not the most elegant) using the java reflection:

    import java.lang.reflect.Field;
    
    public class ThemeChanger {
    
    ThemeChanger(Context context){
        Field[] myFields;
        String myFullNameStyle;
        String myNameStyle;
    
        // Get all styles using reflection
        myFields = R.style.class.getFields();
        // Drill in into single style resource
        for (int i=0; i<myFields.length; i++) {
            myFullNameStyle = myFields[i].toString();
            if (myFullNameStyle.length()>0) {
                int pos = myFullNameStyle.lastIndexOf('.');
                if (pos!=-1) {
                    myNameStyle = myFullNameStyle.substring(pos + 1);
                    myNameStyle = myNameStyle.replace('_', '.');
                    int myStyleId = context.getResources().getIdentifier(myNameStyle, "style", context.getPackageName());
                    if (myStyleId != 0) {
                        int myTypeId[] = {R.attr.my_type};
                        String myType = context.obtainStyledAttributes(myStyleId, myTypeId).getString(0);
                        if (myType == "my_theme") {
                            // Do all things with other custom attrs,
                            // like populating a array to use with a menù
                        }
                    }
                }
            }
        }
    }
    }
    

    Anyway, thanks for your effort.