以编程方式更改从 API 响应获取的颜色资源的值

比方说,在我的 API 调用中有一个名为 color的参数。是否有可能编辑或修改现有的 R.colors.color从 API 结果分配颜色?

举个例子:

我调用我的 API,它返回 green,现在我想加载我的应用程序,即(绿色 Toolbar,绿色 TextView颜色,等等) ,这可能吗?

我的第一个想法是:

colors.xml上创建一个名为 demo的条目,然后给它分配一个默认颜色,然后在任何我想要的地方使用这个 demo颜色(ButtonTextView,等等)。然后我想可以用 API 的结果通过编程方式改变这个值,这样我就不需要创建一个 SharedPreferences或类似的东西来避免更多的代码。

就像 @ Y. S.对我说的

不幸的是,您将不得不设置文本的颜色或视图手动无处不在... : (

我希望如果有其他方法做到这一点,因为我不知道我的项目将包含多少 Activities,所以如果有其他方法做到这一点,我很高兴听到其他猜测。

剪辑

我正在尝试@Jared Rummler 的回答,也许我做错了什么... 我创建了一个简单的 Json,我把我的资产,我解析 Json,我把它放在 GlobalConstant,然后我做了一个“简单的应用程序”。

首先,我有一个包含“ your _ special _ color”的 TextView和一个包含“ your _ special _ color”的 Button,然后我把它的返回值放在 GlobalConstant int上如下:

case "your_special_color":
return GlobalConstant.color;

然后我尝试的是我的第一个 Activity有1个 TextView和1个 Button,正如我之前所说,他们有颜色“你的 _ 特殊 _ 颜色”,我不想改变它,但我有一个 Intent在我的 Button打开另一个 Activity,包含相同的,但与 GlobalConstant.color,它没有改变。

我试着这样做(我的第二个活动) :

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

我错过什么了吗?

哦. . 我想通了,我猜是在我的 MainActivity2上做这个?

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

You can't change an app's resources, they are all constants. Instead you can save your color in SharedPrefences and use the color from there.

See How to use SharedPreferences in Android to store, fetch and edit values.

If your app already has a R.color.green defined and you just want to access it based on what API returned you use:

int resourceID = getResources().getIdentifier("green", "color", getPackageName());

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

store hex color codes into sharedpreferences and then use parsecolor function store your all hexcodes of colors into sessions as a string and whenever you want to change color of perticular button ,textview..just retrive that color code from session and use it as
for ex.
session.setString("white","#FFFFFF"); String colorname=session.getString("white");yourtextview.setBackgroundColor(Color.parseColor(colorname);

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.

R class is not supposed to be edited. It merely contains references to your resources.

You will need to set it manually. However, to reduce the burden of setting it manually you can try to use special libraries for preference saving, for instance:

(full list of similar libraries https://android-arsenal.com/tag/75)


Also, you might want to think about another way of applying styles and passing parameters - consider you would want to add some other parameters like height, width etc. For that purpose, you can define custom attribute in themes.xml/styles.xml:

<attr name="demoColor" format="reference|color" />

then define styles:

<style name="BaseActivity">
</style>
<style name="GreenActivity" parent="@style/BaseActivity">
<item name="demoColor">#00cd00</item>
</style>
<style name="RedActivity" parent="@style/BaseActivity">
<item name="demoColor">#ff0000</item>
</style>

then use that color in your xml like this:

... android:background="?demoColor" ...

and switch between GreenActivity and RedActivity styles in Activity.onCreate:

setTheme(isGreenStyle() ? R.style.GreenActivity : R.style.RedActivity)
setContentView(...)

With the above approach, you will be able to easily configure your styles in xml and it should be less code and easier to refactor in future. (You will still need to have one variable in preference to save whether you have green or red style)


Another way, if you want to show demos of your app with different colors is to use build variants / flavors for loading your app with different colors and styles (it is for build time - not runtime):

app/src/main/res/colors.xml

<resources>
<color name="demoColor">#00cd00</color>
</resources>

app/src/buildVariant/res/colors.xml

<resources>
<color name="demoColor">#ff0000</color>
</resources>

Now you can quickly switch between "main" and "buildVariant" in Build Variants menu and launch your app with different "demo" colors. The same way you can customize a lot of other attributes.

Search for "Build Variants" here http://developer.android.com/tools/building/configuring-gradle.html