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


78

假设,在我的API调用中,我有一个称为的参数color。是否可以编辑或修改现有内容R.colors.color以从API结果中分配颜色?

举个例子:

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

我的第一个想法是:

创建一个对项目colors.xmldemo然后分配给它一个默认的颜色,然后用这个demo地方我想颜色(ButtonTextView,等),那么我想这可能是可能与来自API的结果编程修改这个值,所以我不会需要创建一个SharedPreferences或类似的东西,以避免更多的代码。

正如@YS对我说的

不幸的是,您将不得不设置文本的颜色或在任何地方手动查看... :(

我想知道是否还有其他方法可以做,因为我不知道Activities我的项目将包含多少个,所以如果有其他方法可以做到,我很高兴听到其他猜测。

编辑

我正在尝试@Jared Rummler答案,也许我在做错什么...我创建了一个简单的应用程序,然后将其放在Json我的Assets中进行解析,Json然后将其放入GlobalConstant一个“简单的应用程序”。

首先,我有一个TextView和一个Button包含“ your_special_color”的元素,返回的内容GlobalConstant int如下:

case "your_special_color":                
            return GlobalConstant.color; 

那么我试过是我第一次Activity有1TextView和1Button正如我以前说过,他们有颜色“your_special_color”我不想改变它,但我有一个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));

1
您对此有任何解决方案吗?
Tixeon

1
嘿! 您终于解决了吗?我正面临类似的问题!
Rohitesh

按照贾里德解决它的作品我猜
Skizo-ozᴉʞS

1
查看Cyanea以动态更改原色和强调色:github.com/jaredrummler/Cyanea
Jared Rummler,2018年

@JaredRummler您可以添加一个帖子来解释Cyanea的工作原理吗?谢谢。
Q Locker

Answers:


27

如果您查看“访问资源”文档,它说明的是...

在应用程序中提供资源后,可以通过引用其资源ID来应用它。所有资源ID都在Raapt工具自动生成的项目类中定义。

此外,

编译应用程序时,将aapt生成R类,其中包含res/ 目录中所有资源的资源ID 。对于每种资源类型,都有一个R子类(例如,R.drawable对于所有可绘制资源),对于每种类型的资源,都有一个静态整数(例如, R.drawable.icon)。此整数是可用于检索资源的资源ID。

这是什么话,基本上是作为一个认为几乎所有的资源res/目录中被编译并作为不可改变的常量引用。由于这个原因,资源元素的值不能以编程方式/在运行时更改,因为它们是已编译的。与局部/全局变量&相对SharedPreferences,资源元素在程序存储器中表示为固定的,不可更改的对象。它们保存在程序存储器的特殊只读区域中。在这方面,另请参阅以编程方式更改R.String的值

可以做的是,为避免在项目的一千个位置使用相同的代码,请创建一个通用函数来更改中的颜色值,并在SharedPreferences各处使用此方法。我确定您当然已经知道了。

为了减少您需要添加到项目中的代码量,有另一种方法。我以前使用过书法库,它使我可以在整个应用程序中修复字体样式和颜色。这可能对您很有用,请查看...


所以你对我说不可能做到这一点...?然后,我必须在每个活动的每个片段上创建视图的颜色?
Skizo-ozᴉʞS

是的,你不能那样做。但是您不必重复创建颜色,可以在一个通用的基类中创建颜色,并将该值保留为可以在任何地方使用的全局变量。不幸的是,您 不得不设置文本的颜色或在任何地方手动查看... :(
YS 2015年

是的,我的意思是...我可以将值保存在sharedpref上,然后创建一个全局声明来声明颜色,但是然后...所有setcolor设置背景都非常需要...如果有以下情况,我将尝试在其他地方找到另一种解决方案我没有找到任何我会做你说什么@YS
Skizo-ozᴉʞS

通过de api的这个我也可以获得字体?
Skizo-ozᴉʞS

您是说我可以为应用分配字体然后声明颜色吗?
Skizo-ozᴉʞS

68

您可以创建一个扩展Resources并覆盖方法getColor(int)和的类getColor(int, Theme)

例:

colors.xml

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

资源库

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中使用的方法。如果您getResources在活动和主应用程序类中重写,则可以以编程方式更改主题(即使主题是不可变的)。如果需要,请下载该应用程序,然后查看如何从首选项中设置原色,强调色和背景色。


谢谢您的回答!我会仔细阅读它,然后尝试看看它是否是我所需要的,您认为如果我从API调用中获得了一种颜色(int),并且我在所有背景,样式等上都使用了该颜色……我的默认颜色它会显示API的颜色吗?
Skizo-ozᴉʞS

3
我将再等六个小时。请随时给我发送电子邮件,我会帮助您。jared.rummler@gmail.com
Jared Rummler 2015年

9
抱歉,现在是DEPECRATED
Arav K.

1
getColor(int,Theme)未调用
学习者

2
我编写了一个库,该库可以动态更改应用程序的背景色,原色和强调色。图书馆目前尚未开放,但希望我能尽快分享。上面的代码在Android 6.0+上不起作用,因为对资源进行了许多更改。另外,我不再拥有答案中链接的“ Root Check”应用程序。
Jared Rummler '17

13

R类不应该被编辑。它仅包含对您的资源的引用。

您将需要手动设置。但是,为减轻手动设置的负担,您可以尝试使用特殊的库进行首选项保存,例如:

(相似库的完整列表https://android-arsenal.com/tag/75


另外,您可能想考虑另一种应用样式和传递参数的方法-考虑要添加其他一些参数,例如height,width等。为此,您可以在themes.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" ...

并在中的GreenActivityRedActivity样式之间切换Activity.onCreate

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”颜色启动您的应用程序。您可以使用相同的方式自定义许多其他属性。

在此处http://developer.android.com/tools/building/configuring-gradle.html中搜索“构建变体”


哦,还没有听说过。。。如果我使用buildvariant,可以通过编程方式更改值吗?
Skizo-ozᴉʞS

@Skizo构建变体/口味不是用于以编程方式更改值-它们使您可以使用不同的样式/颜色/资源来构建和运行您的应用程序。看来我从您的问题中“以编程方式”错过了一部分:)我将稍作更新。如果您可以指定要尝试实现的功能的实际使用,这将有所帮助。也许有更好的方法可以做到这一点。
GregoryK

好吧,我只想保存颜色,而不是样式。
Skizo-ozᴉʞS

我懂了。添加了两个首选项库,因此您可以考虑使用它们,因为它们允许绑定首选项-这可能有助于减少代码。
GregoryK 2015年

这正是我在寻找的东西!你是个天才!它使您可以在布局和代码中使用颜色。这是在代码中使用它的一个好例子:stackoverflow.com/questions/17277618/…–
bentzy

10

您无法更改应用程序的资源,它们都是常量。相反,您可以将颜色保存在SharedPrefences中,然后从那里使用颜色。

请参阅如何在Android中使用SharedPreferences来存储,获取和编辑值

如果您的应用程序已经定义了R.color.green,而您只想根据返回的API来访问它,则可以使用:

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

我知道SharedPreferences,我想您没有得到我,我的意思是您可以创建一个文件,colors.xml对吗?然后用十六进制创建带有颜色的项目,然后我想知道是否可以通过编程方式修改此值,以首先放置演示颜色,然后放置真实颜色。
Skizo-ozᴉʞS

您无法在运行时更改colors.xml的内容,而是可以将所有可能的颜色保留在其中,并使用getIdentifier获取API返回的颜色。您可以将所选颜色保留在SharedPref中,并在下一个会话中稍后检索它,直到API调用完成为止
Sourabh 2015年

是的,但是如何设置textView或按钮的textColor?如果我有10个Textviews,我想将它们放在绿色的文字我已经把每个的setText(JAVA)和asigning从SharedPreferences值...?
Skizo-ozᴉʞS

是的,那是唯一的方法。此外,更改资源以后可能会导致您的应用程序出现各种混乱
Sourabh 2015年

3

将十六进制颜色代码存储到sharedpreferences中,然后使用parsecolor函数将所有颜色的十六进制代码作为字符串存储到会话中,并且每当您想要更改特定按钮,textview的颜色时,只需从会话中检索该颜色代码并将其用作
ex。
session.setString("white","#FFFFFF"); String colorname=session.getString("white");yourtextview.setBackgroundColor(Color.parseColor(colorname);


那是什么?您能解释一下您的代码吗?
Skizo-ozᴉʞS
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.