以编程方式更改从 API 响应获得的颜色资源的值
Programmatically change the value of a color resource obtained from API response
比方说,在我的 API 调用中,我有一个名为 color
的参数。是否可以编辑或修改现有的 R.colors.color
以从 API 结果分配颜色?
举个例子:
我打电话给我的 API 并且它 returns green
,现在我想加载我的应用程序,即 (green Toolbar
, green TextView
颜色等),可以吗?
我的第一个想法是:
在 colors.xml
上创建一个名为 demo
的项目,然后为其指定默认颜色,然后在任何我想要的地方使用此 demo
颜色(Button
、TextView
,等等)然后我认为可以使用 API 的结果以编程方式更改此值,这样我就不需要创建 SharedPreferences
或类似的东西并避免更多代码.
正如@Y.S.对我说的
Unfortunately, you WILL have to set the color of the text or view manually everywhere ... :(
我想知道是否有其他方法可以做到这一点,因为我不知道我的项目将包含多少 Activities
,所以如果有其他方法可以做到这一点,我很高兴听到其他猜测。
编辑
我正在尝试@Jared Rummler 的回答,也许我做错了什么...我创建了一个简单的 Json
并放置了我的资产,我解析了 Json
我把它放在 GlobalConstant
然后我做了 "simple app".
首先我有一个 TextView
和一个包含 "your_special_color" 的 Button
和其中的 return 我把 GlobalConstant int
作为如下:
case "your_special_color":
return GlobalConstant.color;
然后我尝试的是我的第一个 Activity
有 1 个 TextView
和 1 个 Button
正如我之前所说,它们有我没有的颜色 "your_special_color"想更改它,但我的 Button
上有一个 Intent
可以打开另一个 Activity
,其中包含相同但带有 GlobalConstant.color
并且它没有改变。
我尝试这样做(我的第二个 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);
}
我是不是漏掉了什么?
哦..我想通了我猜是在我的 MainActivity2
上这样做吗?
Button btn = (Button)findViewById(R.id.button2);
btn.setBackgroundColor(res.getColor(R.color.your_special_color));
您无法更改应用的资源,它们都是常量。相反,您可以将颜色保存在 SharedPrefences 中并使用那里的颜色。
参见How to use SharedPreferences in Android to store, fetch and edit values。
如果您的应用已经定义了 R.color.green,而您只想根据 API 返回的内容访问它,请使用:
int resourceID = getResources().getIdentifier("green", "color", getPackageName());
如果你看一下 Accessing Resources 文档,它说的是......
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.
此外,
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.
这基本上是说 res/
目录中几乎所有作为 资源 保存的内容都被编译并引用为不可更改的常量。正是由于这个原因,资源元素的值无法在运行时更改programmatically/at,因为它们是编译。与 local/global 变量和 SharedPreferences
相反,资源元素在程序内存中表示为固定的、不可更改的对象。它们保存在程序存储器的一个特殊的只读区域中。在这方面,另请参阅 Changing value of R.String Programmatically.
您可以做的是,为了避免在项目中的一千个地方使用相同的代码,创建一个通用函数来更改 SharedPreferences
到处使用这个方法。当然,我相信你已经知道了。
要减少需要添加到项目中的代码量,有一个替代方法。我之前使用过 calligraphy library,它允许我在整个应用程序中修复字体样式和颜色。这可能对你有用,看看吧...
将十六进制颜色代码存储到 sharedpreferences 中,然后使用 parsecolor 函数将所有十六进制颜色代码作为字符串存储到会话中,并且每当您想要更改特定按钮、文本视图的颜色时,只需从会话中检索该颜色代码并使用它作为
例如
session.setString("white","#FFFFFF");
String colorname=session.getString("white");yourtextview.setBackgroundColor(Color.parseColor(colorname);
您可以创建一个 class 来扩展 Resources
并覆盖方法 getColor(int)
和 getColor(int, Theme)
.
示例:
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;
}
...
}
这是我在我的一个应用程序 Root Check 中使用的方法。如果您在活动和主应用程序 class 中覆盖 getResources
,您可以通过编程方式更改主题(即使主题是不可变的)。如果需要,请下载该应用程序并查看如何根据首选项设置主色、强调色和背景色。
R
class 不应该被编辑。它仅包含对您的资源的引用。
您需要手动设置。但是,为了减少手动设置的负担,您可以尝试使用特殊的库来保存首选项,例如:
- 军刀 - https://github.com/jug6ernaut/saber
- PreferenceBinder - https://github.com/denley/preferencebinder
(类似库的完整列表 https://android-arsenal.com/tag/75)
此外,您可能想考虑另一种应用样式和传递参数的方式 - 考虑您想要添加一些其他参数,如高度、宽度等。为此,您可以在主题中定义自定义属性。xml/styles.xml:
<attr name="demoColor" format="reference|color" />
然后定义样式:
<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>
然后像这样在 xml 中使用该颜色:
... android:background="?demoColor" ...
并在 Activity.onCreate
中的 GreenActivity
和 RedActivity
样式之间切换:
setTheme(isGreenStyle() ? R.style.GreenActivity : R.style.RedActivity)
setContentView(...)
通过上述方法,您将能够轻松地在 xml 中配置您的样式,并且代码应该更少,并且将来更容易重构。 (你仍然需要有一个变量来保存你是绿色还是红色风格)
另一种方法,如果你想用不同的颜色展示你的应用程序的演示,是使用构建变体/风格来加载你的具有不同颜色和样式的应用程序(它是针对构建时间 - 而不是运行时):
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>
现在您可以在 Build Variants 菜单中在 "main" 和 "buildVariant" 之间快速切换,并使用不同的 "demo" 颜色启动您的应用程序。同样的方法你可以自定义很多其他的属性。
在此处搜索 "Build Variants" http://developer.android.com/tools/building/configuring-gradle.html
比方说,在我的 API 调用中,我有一个名为 color
的参数。是否可以编辑或修改现有的 R.colors.color
以从 API 结果分配颜色?
举个例子:
我打电话给我的 API 并且它 returns green
,现在我想加载我的应用程序,即 (green Toolbar
, green TextView
颜色等),可以吗?
我的第一个想法是:
在 colors.xml
上创建一个名为 demo
的项目,然后为其指定默认颜色,然后在任何我想要的地方使用此 demo
颜色(Button
、TextView
,等等)然后我认为可以使用 API 的结果以编程方式更改此值,这样我就不需要创建 SharedPreferences
或类似的东西并避免更多代码.
正如@Y.S.对我说的
Unfortunately, you WILL have to set the color of the text or view manually everywhere ... :(
我想知道是否有其他方法可以做到这一点,因为我不知道我的项目将包含多少 Activities
,所以如果有其他方法可以做到这一点,我很高兴听到其他猜测。
编辑
我正在尝试@Jared Rummler 的回答,也许我做错了什么...我创建了一个简单的 Json
并放置了我的资产,我解析了 Json
我把它放在 GlobalConstant
然后我做了 "simple app".
首先我有一个 TextView
和一个包含 "your_special_color" 的 Button
和其中的 return 我把 GlobalConstant int
作为如下:
case "your_special_color":
return GlobalConstant.color;
然后我尝试的是我的第一个 Activity
有 1 个 TextView
和 1 个 Button
正如我之前所说,它们有我没有的颜色 "your_special_color"想更改它,但我的 Button
上有一个 Intent
可以打开另一个 Activity
,其中包含相同但带有 GlobalConstant.color
并且它没有改变。
我尝试这样做(我的第二个 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);
}
我是不是漏掉了什么?
哦..我想通了我猜是在我的 MainActivity2
上这样做吗?
Button btn = (Button)findViewById(R.id.button2);
btn.setBackgroundColor(res.getColor(R.color.your_special_color));
您无法更改应用的资源,它们都是常量。相反,您可以将颜色保存在 SharedPrefences 中并使用那里的颜色。
参见How to use SharedPreferences in Android to store, fetch and edit values。
如果您的应用已经定义了 R.color.green,而您只想根据 API 返回的内容访问它,请使用:
int resourceID = getResources().getIdentifier("green", "color", getPackageName());
如果你看一下 Accessing Resources 文档,它说的是......
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 theaapt
tool automatically generates.
此外,
When your application is compiled,
aapt
generates theR
class, which contains resource IDs for all the resources in yourres/
directory. For each type of resource, there is anR
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.
这基本上是说 res/
目录中几乎所有作为 资源 保存的内容都被编译并引用为不可更改的常量。正是由于这个原因,资源元素的值无法在运行时更改programmatically/at,因为它们是编译。与 local/global 变量和 SharedPreferences
相反,资源元素在程序内存中表示为固定的、不可更改的对象。它们保存在程序存储器的一个特殊的只读区域中。在这方面,另请参阅 Changing value of R.String Programmatically.
您可以做的是,为了避免在项目中的一千个地方使用相同的代码,创建一个通用函数来更改 SharedPreferences
到处使用这个方法。当然,我相信你已经知道了。
要减少需要添加到项目中的代码量,有一个替代方法。我之前使用过 calligraphy library,它允许我在整个应用程序中修复字体样式和颜色。这可能对你有用,看看吧...
将十六进制颜色代码存储到 sharedpreferences 中,然后使用 parsecolor 函数将所有十六进制颜色代码作为字符串存储到会话中,并且每当您想要更改特定按钮、文本视图的颜色时,只需从会话中检索该颜色代码并使用它作为
例如
session.setString("white","#FFFFFF");
String colorname=session.getString("white");yourtextview.setBackgroundColor(Color.parseColor(colorname);
您可以创建一个 class 来扩展 Resources
并覆盖方法 getColor(int)
和 getColor(int, Theme)
.
示例:
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;
}
...
}
这是我在我的一个应用程序 Root Check 中使用的方法。如果您在活动和主应用程序 class 中覆盖 getResources
,您可以通过编程方式更改主题(即使主题是不可变的)。如果需要,请下载该应用程序并查看如何根据首选项设置主色、强调色和背景色。
R
class 不应该被编辑。它仅包含对您的资源的引用。
您需要手动设置。但是,为了减少手动设置的负担,您可以尝试使用特殊的库来保存首选项,例如:
- 军刀 - https://github.com/jug6ernaut/saber
- PreferenceBinder - https://github.com/denley/preferencebinder
(类似库的完整列表 https://android-arsenal.com/tag/75)
此外,您可能想考虑另一种应用样式和传递参数的方式 - 考虑您想要添加一些其他参数,如高度、宽度等。为此,您可以在主题中定义自定义属性。xml/styles.xml:
<attr name="demoColor" format="reference|color" />
然后定义样式:
<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>
然后像这样在 xml 中使用该颜色:
... android:background="?demoColor" ...
并在 Activity.onCreate
中的 GreenActivity
和 RedActivity
样式之间切换:
setTheme(isGreenStyle() ? R.style.GreenActivity : R.style.RedActivity)
setContentView(...)
通过上述方法,您将能够轻松地在 xml 中配置您的样式,并且代码应该更少,并且将来更容易重构。 (你仍然需要有一个变量来保存你是绿色还是红色风格)
另一种方法,如果你想用不同的颜色展示你的应用程序的演示,是使用构建变体/风格来加载你的具有不同颜色和样式的应用程序(它是针对构建时间 - 而不是运行时):
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>
现在您可以在 Build Variants 菜单中在 "main" 和 "buildVariant" 之间快速切换,并使用不同的 "demo" 颜色启动您的应用程序。同样的方法你可以自定义很多其他的属性。
在此处搜索 "Build Variants" http://developer.android.com/tools/building/configuring-gradle.html