Ändern Sie programmgesteuert den Wert einer Farbressource, die aus der API-Antwort erhalten wird

78

Angenommen, ich habe bei meinem API-Aufruf einen Parameter, der aufgerufen wird color. Ist es möglich, eine vorhandene zu bearbeiten oder zu ändern R.colors.color, um die Farbe aus dem API-Ergebnis zuzuweisen?

Als Beispiel:

Ich rufe meine API auf und sie kehrt zurück green. Jetzt möchte ich meine App mit dh (grün Toolbar, grüne TextViewFarbe usw.) laden. Ist das möglich?

Mein erster Gedanke war:

Erstellen Sie auf ein Element colors.xmlnamens demodann eine Standardfarbe zuweisen, dann diese verwenden demoFarbe wohin ich will ( Button, TextViewusw.) Dann dachte ich , könnte es möglich sein , diesen Wert zu ändern programmatisch mit dem Ergebnis aus der API so dass ich nicht brauchen würde , Erstellen Sie ein SharedPreferencesoder ähnliches und vermeiden Sie mehr Code.

Wie @YS zu mir sagte

Leider müssen Sie die Farbe des Textes oder der Ansicht überall manuell einstellen ... :(

Ich würde gerne wissen, ob es einen anderen Weg gibt, da ich nicht weiß, wie viele Activitiesmein Projekt enthalten wird. Wenn es also einen anderen Weg gibt, bin ich froh, andere Vermutungen zu hören.

BEARBEITEN

Ich versuche die @ Jared Rummler Antwort und vielleicht mache ich etwas falsch ... Ich habe eine einfache erstellt Jsonund ich habe meine Assets aufgelegt, ich analysiere die Jsonund ich habe sie auf eine gelegt, GlobalConstantdann habe ich eine "einfache App" gemacht.

Zuallererst habe ich ein TextViewund ein, Buttondas die "your_special_color" enthält, und die Rückgabe davon habe ich GlobalConstant intwie folgt ausgedrückt :

case "your_special_color":                
            return GlobalConstant.color; 

Dann habe ich versucht, meine erste Activityhat 1 TextViewund 1, Buttonwie ich bereits sagte, und sie haben die Farbe "your_special_color", die ich nicht ändern möchte, ABER ich habe eine Intentauf meiner Button, um die andere zu öffnen Activity, die die gleiche enthält, aber mit der GlobalConstant.colorund es ändert sich nicht.

Ich habe es dabei versucht (meine zweite Aktivität):

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

Habe ich etwas verpasst?

Oh ... ich habe es herausgefunden, ich denke, macht das auf meinem MainActivity2?

 Button btn = (Button)findViewById(R.id.button2);
 btn.setBackgroundColor(res.getColor(R.color.your_special_color));
Skizo-ozᴉʞS
quelle
1
Hast du eine Lösung dafür bekommen?
Tixeon
1
Hallo! Hast du das endlich gelöst? Ich stehe vor einem ähnlichen Problem!
Rohitesh
Folgen Sie der Jared-Lösung, die funktioniert, denke ich
Skizo-ozᴉʞS
1
Schauen Sie sich Cyanea an, um die Primär- und Akzentfarben dynamisch zu ändern: github.com/jaredrummler/Cyanea
Jared Rummler
@JaredRummler Könnten Sie einen Beitrag hinzufügen, um zu erklären, wie Cyanea funktioniert? Vielen Dank.
Q Locker

Antworten:

27

Wenn Sie sich das Dokument Zugriff auf Ressourcen ansehen , heißt es, dass ...

Sobald Sie eine Ressource in Ihrer Anwendung bereitgestellt haben, können Sie sie anwenden, indem Sie auf ihre Ressourcen-ID verweisen. Alle Ressourcen-IDs werden in der RKlasse Ihres Projekts definiert , die das aaptTool automatisch generiert.

Außerdem,

Wenn Ihre Anwendung kompiliert , aapterzeugt die RKlasse, die Ressourcen - IDs für alle Ressourcen in Ihrem enthält res/ Verzeichnis. Für jeden Ressourcentyp gibt es eine RUnterklasse (z. B. R.drawablefür alle zeichnbaren Ressourcen), und für jede Ressource dieses Typs gibt es eine statische Ganzzahl (z. B. R.drawable.icon). Diese Ganzzahl ist die Ressourcen-ID, mit der Sie Ihre Ressource abrufen können.

Dies bedeutet im Wesentlichen, dass so ziemlich alles, was als Ressource im res/Verzeichnis gespeichert ist, kompiliert und als unveränderliche Konstante referenziert wird. Aus diesem Grund können die Werte von Ressourcenelementen nicht programmgesteuert / zur Laufzeit geändert werden, da sie kompiliert werden . Im Gegensatz zu lokalen / globalen Variablen & SharedPreferenceswerden Ressourcenelemente im Programmspeicher als feste, unveränderliche Objekte dargestellt. Sie befinden sich in einem speziellen schreibgeschützten Bereich des Programmspeichers. Siehe hierzu auch Ändern des Werts von R.String Programmatisch .

Was Sie können tun , ist, zu vermeiden , an tausend Stellen mit dem gleichen Code in Ihrem Projekt, erstellen Sie eine gemeinsame Funktion, die den Wert der Farbe in der ändert SharedPreferencesund diese Methode überall benutzen. Ich bin mir sicher, dass Sie das schon gewusst haben.

Um die Menge an Code zu reduzieren, die Sie dem Projekt hinzufügen müssen, gibt es eine Alternative. Ich habe zuvor die Kalligraphiebibliothek verwendet, mit der ich den Schriftstil und die Farbe in der gesamten App korrigieren konnte. Dies kann für Sie von Nutzen sein, probieren Sie es aus ...

YS
quelle
Sie sagen mir also, dass das nicht möglich ist ...? Dann muss ich auf jedem Fragment bei jeder Aktivität die Farbe für die Ansicht erstellen?
Skizo-ozᴉʞS
Das stimmt, das kannst du nicht. Sie müssen die Farbe jedoch nicht wiederholt erstellen, sondern können sie in einer gemeinsamen Basisklasse erstellen und den Wert als globale Variable beibehalten, die Sie überall verwenden können. Leider haben Sie WILL die Farbe des Textes oder Ansicht manuell überall setzen müssen ... :(
YS
Ja das, was ich meinte ... Ich kann den Wert auf sharedpref speichern und dann eine globale Klausel erstellen, um die Farbe zu deklarieren, aber dann ... Der gesamte Setcolor-Set-Hintergrund wird gut benötigt ... Ich werde versuchen, irgendwo eine andere Lösung zu finden, wenn Ich finde keine Ich werde tun, was Sie sagen @YS
Skizo-ozᴉʞS
Mit diesem von de api kann ich auch eine Schrift bekommen?
Skizo-ozᴉʞS
Meinen Sie damit, dass ich der App eine Schriftart zuweisen und dann die Farbe deklarieren kann?
Skizo-ozᴉʞS
68

Sie können eine Klasse erstellen, die Resourcesdie Methoden getColor(int)und erweitert und überschreibt getColor(int, Theme).

Beispiel:

Farben.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;
    }

    ...

}

Dies ist der Ansatz, den ich in einer meiner Apps, Root Check, verwendet habe . Wenn Sie getResourcesIhre Aktivitäten und die Hauptanwendungsklasse überschreiben , können Sie das Thema programmgesteuert ändern (obwohl Themen unveränderlich sind). Wenn Sie möchten, laden Sie die App herunter und sehen Sie, wie Sie die Primär-, Akzent- und Hintergrundfarben in den Einstellungen festlegen können.

Jared Rummler
quelle
Danke für deine Antwort! Ich werde es sorgfältig lesen und versuchen zu sehen, ob es das ist, was ich brauche. Dabei denken Sie, wenn ich eine Farbe (int) von einem API-Aufruf erhalte und auf allen meinen Hintergründen, Stilen usw. meine Standardfarbe verwende wird die Farbe der API angezeigt?
Skizo-ozᴉʞS
3
Ich werde für weitere 6 Stunden nicht verfügbar sein. Fühlen Sie sich frei, mir eine E-Mail zu senden, und ich werde Ihnen helfen. [email protected]
Jared Rummler
9
Sorry Leute, aber das ist jetztDEPECRATED
Arav K.
1
getColor (int, Theme) ruft nicht an
Lernender
2
Ich habe eine Bibliothek geschrieben, die die Hintergrund-, Primär- und Akzentfarben einer App dynamisch ändert. Die Bibliothek ist derzeit nicht geöffnet, aber ich hoffe, ich kann sie bald teilen. Der obige Code funktioniert unter Android 6.0+ nicht, da viele Änderungen an den Ressourcen vorgenommen wurden. Außerdem besitze ich nicht mehr die Root Check-App, die in der Antwort verlinkt ist.
Jared Rummler
13

RKlasse soll nicht bearbeitet werden. Es enthält lediglich Verweise auf Ihre Ressourcen.

Sie müssen es manuell einstellen. Um die manuelle Einstellung zu verringern, können Sie versuchen, spezielle Bibliotheken zum Speichern von Einstellungen zu verwenden, z. B.:

(vollständige Liste ähnlicher Bibliotheken https://android-arsenal.com/tag/75 )


Möglicherweise möchten Sie auch über eine andere Methode zum Anwenden von Stilen und Übergeben von Parametern nachdenken. Denken Sie daran, dass Sie einige andere Parameter wie Höhe, Breite usw. hinzufügen möchten. Zu diesem Zweck können Sie ein benutzerdefiniertes Attribut in der Datei theme.xml / styles.xml definieren:

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

Definieren Sie dann Stile:

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

Verwenden Sie dann diese Farbe in Ihrer XML wie folgt:

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

und wechseln Sie zwischen GreenActivityund RedActivityStile in Activity.onCreate:

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

Mit dem oben beschriebenen Ansatz können Sie Ihre Stile problemlos in XML konfigurieren. Es sollte weniger Code enthalten und in Zukunft einfacher umzugestalten sein. (Sie müssen immer noch eine Variable bevorzugen, um zu speichern, ob Sie einen grünen oder einen roten Stil haben.)


Wenn Sie Demos Ihrer App mit verschiedenen Farben anzeigen möchten, können Sie auch Build-Varianten / -Varianten verwenden, um Ihre App mit verschiedenen Farben und Stilen zu laden (dies gilt für die Build-Zeit - nicht für die Laufzeit):

app / src / main / res / colours.xml

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

app / src / buildVariant / res / colours.xml

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

Jetzt können Sie im Menü "Varianten erstellen" schnell zwischen "main" und "buildVariant" wechseln und Ihre App mit verschiedenen "Demofarben" starten. Auf die gleiche Weise können Sie viele andere Attribute anpassen.

Suchen Sie hier nach "Build Variants" http://developer.android.com/tools/building/configuring-gradle.html

GregoryK
quelle
Oh, ich habe nichts davon gehört ... Also kann ich den Wert programmgesteuert ändern, wenn ich die Build-Variante verwende?
Skizo-ozᴉʞS
@ Skizo-Build-Varianten / -Varianten dienen nicht dazu, den Wert programmgesteuert zu ändern. Sie ermöglichen es Ihnen, Ihre App mit verschiedenen Stilen / Farben / Ressourcen zu erstellen und auszuführen. Es scheint, dass ich einen "programmgesteuerten" Teil Ihrer Fragen verpasst habe :) Ich werde meine Antwort ein wenig aktualisieren. Es wäre hilfreich, wenn Sie die tatsächliche Verwendung der Funktionalität angeben könnten, die Sie implementieren möchten. Vielleicht gibt es einen besseren Weg, es zu tun.
GregoryK
Nun, ich möchte nur die Farbe speichern, nicht den Stil.
Skizo-ozᴉʞS
Aha. Es wurden einige Voreinstellungsbibliotheken hinzugefügt, sodass Sie sie möglicherweise verwenden können, da sie das Binden von Voreinstellungen ermöglichen. Dies kann bei der Reduzierung des Codes hilfreich sein.
GregoryK
Genau das habe ich gesucht !!! Du bist ein Genie! Sie haben die Möglichkeit, Farben auch in Layouts und im Code zu verwenden. Hier ist ein gutes Beispiel, um es im Code zu verwenden: stackoverflow.com/questions/17277618/…
bentzy
10

Sie können die Ressourcen einer App nicht ändern, sie sind alle Konstanten. Stattdessen können Sie Ihre Farbe in SharedPrefences speichern und die Farbe von dort aus verwenden.

Siehe Verwenden von SharedPreferences in Android zum Speichern, Abrufen und Bearbeiten von Werten .

Wenn in Ihrer App bereits ein R.color.green definiert ist und Sie nur auf der Grundlage der von Ihnen verwendeten API darauf zugreifen möchten:

int resourceID = getResources().getIdentifier("green", "color", getPackageName());
Sourabh
quelle
Ich weiß von SharedPreferencesund ich denke, Sie haben mich nicht verstanden. Ich meinte, Sie können eine Datei mit dem Namen colors.xmlrichtig erstellen . und dann darauf Elemente mit Farben mit HEX erstellen, dann würde ich gerne wissen, ob ich diesen Wert programmgesteuert ändern kann, um zuerst die Demofarbe und dann die echte Farbe zu setzen.
Skizo-ozᴉʞS
Sie können den Inhalt von colours.xml zur Laufzeit nicht ändern. Stattdessen können Sie alle möglichen Farben darin behalten und getIdentifier verwenden, um die von der API zurückgegebene Farbe abzurufen. Sie können die ausgewählte Farbe in SharedPref behalten und später in der nächsten Sitzung abrufen, bis der API-Aufruf beendet ist
Sourabh,
Ja, aber wie kann man die Textfarbe einer Textansicht oder einer Schaltfläche einstellen? Wenn ich 10 Textansichten habe und sie auf grünen Text setzen möchte, muss ich den setText (Java) für jede setzen und den Wert von SharedPreferences zuweisen? ...
Skizo-ozᴉʞS
Ja, das ist der einzige Weg.
Sourabh,
3

Speichern Sie hexadezimale Farbcodes in gemeinsam genutzten Einstellungen und verwenden Sie dann die Parsecolor-Funktion. Speichern Sie alle hexadezimalen Farbcodes in Sitzungen als Zeichenfolge. Wenn Sie die Farbe der jeweiligen Schaltfläche, der Textansicht ändern möchten, rufen Sie diesen Farbcode einfach aus der Sitzung ab und verwenden Sie ihn wie
z.
session.setString("white","#FFFFFF"); String colorname=session.getString("white");yourtextview.setBackgroundColor(Color.parseColor(colorname);

Mayuresh Gawande
quelle
Was ist das? Können Sie Ihren Code ein wenig erläutern?
Skizo-ozᴉʞS