Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)); 
like image 819
Skizo-ozᴉʞS Avatar asked Nov 29 '15 20:11

Skizo-ozᴉʞS


People also ask

How do I change color programmatically?

Android TextView – Text Color. TextView Text Color – To change the color of text in TextView, you can set the color in layout XML file using textColor attribute or change the color dynamically in Kotlin file using setTextColor() method.

What is ColorStateList?

A ColorStateList is an object you can define in XML that you can apply as a color, but will actually change colors, depending on the state of the View object to which it is applied.


2 Answers

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.

like image 193
Jared Rummler Avatar answered Sep 21 '22 17:09

Jared Rummler


If you take a look at the Accessing Resources document, what it says is that ...

Once you provide a resource in your application, you can apply it by referencing its resource ID. All resource IDs are defined in your project's R class, which the aapt tool automatically generates.

Furthermore,

When your application is compiled, aapt generates the R class, which contains resource IDs for all the resources in your res/ directory. For each type of resource, there is an R subclass (for example, R.drawable for all drawable resources), and for each resource of that type, there is a static integer (for example, R.drawable.icon). This integer is the resource ID that you can use to retrieve your resource.

What this is saying, essentially, is that pretty much everything held as a resource in the res/ directory is compiled and referenced as an unchangeable constant. It is for this reason that the values of resource elements cannot be changed programmatically/at runtime, because they are compiled. As opposed to local/global variables & SharedPreferences, resource elements are represented in program memory as fixed, unchangeable objects. They are held in a special read-only region of program memory. In this regard, see also Changing value of R.String Programmatically.

What you can do is, to avoid using the same code at a thousand places in your project, create a common function that changes the value of the color in the SharedPreferences and use this method everywhere. I'm sure you knew this already, of course.

To reduce the amount of code you need to add to the project, there is an alternative. I have previously used the calligraphy library which allowed me to fix the font style & color throughout the app. This may be of some good use to you, check it out ...

like image 38
Y.S Avatar answered Sep 19 '22 17:09

Y.S