Programmatically change the value of a color resource obtained from API response

Skizo-ozᴉʞS picture Skizo-ozᴉʞS · Nov 29, 2015 · Viewed 62.1k times · Source

Let's say, on my API call I have a parameter that's called color. Is it possible to edit or modify an existent R.colors.color to assign the color from the API result?

As an example:

I make a call to my API and it returns green, now I want to load my app with i.e (green Toolbar, green TextView color, etc.), is that possible?

My first thought was:

Create a item on colors.xml called demo then assign it a default color, then use this demo color wherever I want (Button, TextView, etc.) Then I thought it could be possible to change this value programmatically with the result from the API so I wouldn't need to create a SharedPreferences or something like that and for avoiding more code.

As @Y.S. said to me

Unfortunately, you WILL have to set the color of the text or view manually everywhere ... :(

I would like if there is other way to do it, since I don't know how many Activities my project will contain, so if is there other way to do it I'm glad to hear other guesses.

EDIT

I'm trying the @Jared Rummler answer and maybe i'm doing something wrong... I've created a simple Json and I put on my Assets I parse the Json and I put it on a GlobalConstant then I made a "simple app".

First of all I have a TextView and a Button which contains the "your_special_color", and the return of it I put the GlobalConstant int as follows :

case "your_special_color":                
            return GlobalConstant.color; 

Then what I tried is my first Activity has 1 TextView and 1 Button as I said before and they have the color "your_special_color" that I don't want to change it, BUT I have an Intent on my Button to open the other Activity that contains the same but with the GlobalConstant.color and it doesn't change.

I tried it doing this (my second Activity):

public class Main2Activity extends AppCompatActivity {
private Res res;
@Override public Resources getResources() {
    if (res == null) {
        res = new Res(super.getResources());
    }
    return res;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
}

Did I miss something?

Oh.. I figured it out I guess is doing this on my MainActivity2 ?

 Button btn = (Button)findViewById(R.id.button2);
 btn.setBackgroundColor(res.getColor(R.color.your_special_color));

Answer

Jared Rummler picture Jared Rummler · Dec 9, 2015

You can create a class which extends Resources and override the methods getColor(int) and getColor(int, Theme).

Example:

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="your_special_color">#FF0099CC</color>
</resources>

Res.java

public class Res extends Resources {

    public Res(Resources original) {
        super(original.getAssets(), original.getDisplayMetrics(), original.getConfiguration());
    }

    @Override public int getColor(int id) throws NotFoundException {
        return getColor(id, null);
    }

    @Override public int getColor(int id, Theme theme) throws NotFoundException {
        switch (getResourceEntryName(id)) {
            case "your_special_color":
                // You can change the return value to an instance field that loads from SharedPreferences.
                return Color.RED; // used as an example. Change as needed.
            default:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    return super.getColor(id, theme);
                }
                return super.getColor(id);
        }
    }
}

BaseActivity.java

public class BaseActivity extends AppCompatActivity {

    ...

    private Res res;

    @Override public Resources getResources() {
        if (res == null) {
            res = new Res(super.getResources());
        }
        return res;
    }

    ...

}

This is the approach I have used in one of my apps, Root Check. If you override getResources in your activities and main application class you can change the theme programmatically (even though themes are immutable). If you want, download the app and see how you can set the primary, accent, and background colors from preferences.