button.setBackgroundColor(), was muss ich beachten?

  • 9 Antworten
  • Letztes Antwortdatum
raptus93

raptus93

Neues Mitglied
0
Was muss ich beachten, wenn ich bei einem Button die BackgroundColor setten will? Folgende Situation:
Ich baue ein Quiz und die Antworten sollen grün bzw rot werden, wenn die Antwort richtig bzw falsch ist.
Dafür unterscheide ich 8 verschiedene Fälle, für jede der vier Antworten einen richtigen und einen falschen.
Die Objektreferenzen für die Views ließ ich mir gerade ausgeben, und sie sind != null. Ich habe auch keinen Grund zu der Annahme, dass ich eine Kopie bearbeite, und das Original unberührt bleibt.
Der Codeblock wird definitiv ausgeführt, denn ich gebe Toasts aus, die in jedem der 8 Fälle unterschiedlich sind, und passend angezeigt werden.
In der .xml habe ich keine Farbe zugewiesen, und die erste Farbzuweisung funktioniert (auf Default-Answer), dann jedoch keine weitere mehr.
WORAN LIEGT DAS? IST DAS EIN GÄNGIGES PROBLEM?
Ich rage schon, weil ich seit Tagen nichts mehr zu Stande kriege außer dieses Problem zu googlen!
Was wollt ihr wissen, um mir sagen zu können, worauf ich achten muss? Ich kann auch Code schicken, wenn jemand bei Fehlerfinden helfen will!

Danke im Vorraus,

Gruß raptus93
 
Hi, ich weiß zwar nicht wie genau du es versucht hast, aber teste doch mal bitte folgendes:

Ich habe mir testweise grade eben eine green.xml im Ordner "res>drawable" angelegt.

Darein schreibe ich:
<?XML version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android: color="#00GG00" />
</shape>

In deiner Activity:

Button btnTest123;
btnTest123 = (Button)findViewById(R.Id.btnTest123);
btnTest123.setBackgroundResource(R.drawable.green);


Jetzt würde jeder erfahrene Programmierer sagen das es sehr umständlich ist, aber ich finde es so besser, da man über die XML den button sehr individuell gestalten kann

<?XML version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gratient android: startColor="#00FF00"
android:endColor="#FF0000"
android: angle="90" />
</shape>


Da hätten wir jetzt zB einen Farbverlauf von links nach rechts drin, er fängt links mit grün an und wird dann nach rechts hin rot.

Eventuell klappt das ja so wie du es dir vorstellst ;)
 
Zuletzt bearbeitet:
Hello,
ja du ringst schon seit Tagen und ich verstehe auch den Sinn nicht nochmal einen neuen Thread aufzumachen - aber nun ja.

Zu deiner Frage:
Erstmal ist es doch schon mal gut, dass dein Programm teilweise schon funktioniert - immerhin etwas. :)
Dein Problem ist mehr oder weniger "gängig"... Für einen Anfänger ist es aber nicht untypisch, dass erstmal vieles verkehrt bzw. gar nicht läuft. Ging mir jedenfalls eine ganze Weile genauso. Deswegen Ruhe bewahren, das wird schon. ;)

So wie ich es verstehe, willst du es so machen, dass der Button gedrückt wird -> Farbe ändern und diese Farbänderung soll auch mehrmals hintereinander funktionieren (ggf mit Verzögerung - aber das lassen wir für das "Verständnis" erstmal weg).
Also wenn du programmierst: "bei Button-Änderung -> Farbe wechseln" dann ist die Folge daraus, dass der Button (nun jetzt) gedrückt wurde und somit der "Listener" (also die Abfrage stattgefunden HAT) - also abgearbeitet IST.
Entweder springst du jetzt in deinem Programm zu einem Ausgangszustand wieder zurück oder implementierst eine komplett neue "Logik" die deine Funktionen wieder gangbar macht.

Btw: Hast du wirklich 8 Unterscheidungsfälle oder 4x einen Boolean, das dann ein gewisses "Ergebnis" / Ereignis auslöst? Die Frage habe ich absichtlich mal etwas "unpräzise" gestellt. Für mich klingt es so als ob dein Code viel Potenzial zur Optimierung hat^^

Zeig mal deinen Code. ;)

@joshua: hehe, jo da scheiden sich wohl die Geister. Bei Abfragen, oder der "Button gedrückt" ist, lade ich auch verschiedene xml-Files. Bei Farbänderungen hingegen bin ich Verfechter der Implementierung im "Code". Spezielle Vor- und Nachteile gibt es wahrscheinlich nicht und wenn sind diese nicht schwerwiegend. Allerdings fällt mir persönlich die Variante im Code leichter, da ich so alles schön kompakt im Code einstellen kann ohne die Dateiansicht wechseln zu müssen (gerade bei Farbänderungen meiner Meinung nach ein Vorteil).
 
Zuletzt bearbeitet:
Feine Sache, das werde ich gleich ausprobieren, danke!

Ich glaube ich bin dem Problem auf die schliche gekommen, warum es auf meine Art und Weise nicht funktioniert, aber kenne nicht die Lösung dafür:

Wenn ich eine Farbe zuweisen, warte ich 1200ms und weise dann wieder die ursprüungliche Farbe zu. Android scheint der Meinung zu sein, dass es sich dann garnicht lohnt zu switchen, und tut es einfach nicht.

Ich habe die 1200ms über einen Callback realisiert.

Kennt jemand die Lösung, wie ich eine Farbe für eine bestimmte Dauer zuweisen, dann aber wieder zurück auf default stellen kann, ohne dass android 'sich das direkt spart'?

Der ursprüngliche Beitrag von 18:52 Uhr wurde um 19:02 Uhr ergänzt:

@ UI, sorry, dein Beitrag kam grade erst dazu, während ich meinen verfasst habe, also hier die dir gebührende Antwort:

Wenn Button gedrückt -> onClick -> Highlight -> Wartezeit -> Callback -> Buttons auf Default

hier der relavante Code:
Code:
//imports

public class QuizGUI extends Activity implements OnClickListener{
    
    private TextView tvQuestion;
    private Button btnAnswerA;
    private Button btnAnswerB;
    private Button btnAnswerC;
    private Button btnAnswerD;
    private ProgressBar timePB;
    
    private QuizLogic logic;
        
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_quiz);
        
        //Sets up the Views
        setupLayout();
        
        //Initializing the Logic
        logic = new QuizLogic();
        
        //register this as observer
        logic.registerGUI(this);
        
        //Get 10 Questions from the server
        logic.getQuestions();
        
        //Starts the Timer once
        logic.startTimer();
        
        //Create the first Question
        showNextQuestion();
    }
    
    private void setupLayout(){
        
        //Initializing the textView and the buttons
        tvQuestion = (TextView) findViewById(R.id.question);
        btnAnswerA = (Button) findViewById(R.id.answerA);
        btnAnswerB = (Button) findViewById(R.id.answerB);
        btnAnswerC = (Button) findViewById(R.id.answerC);
        btnAnswerD = (Button) findViewById(R.id.answerD);
        timePB = (ProgressBar) findViewById(R.id.timeProgressBar);
        timePB.setMax(logic.TIME_TO_ANSWER);
        timePB.setProgress(logic.TIME_TO_ANSWER);
        
        //Adding the Listener for the Answer-Buttons
        btnAnswerA.setOnClickListener(this);
        btnAnswerB.setOnClickListener(this);
        btnAnswerC.setOnClickListener(this);
        btnAnswerD.setOnClickListener(this);
    }
    
    @Override
    public void onClick(View v) {
        //Decision, what Button has been clicked
        Answer chosenAnswer = Answer.A;
        if (v == btnAnswerB){
            chosenAnswer = Answer.B;
        }
        else if (v == btnAnswerC){
            chosenAnswer = Answer.C;    
        }
        else if (v == btnAnswerD){
            chosenAnswer = Answer.D;
        }
        
        //blockButtons();
        
        //Check the correctness at the server, highlight depending on the result
        if(logic.checkAnswer(chosenAnswer) == true){
            highlight(true, chosenAnswer);
            logic.incrementCorrectAnswers();
        }
        else{
            highlight(false, chosenAnswer);
        }
        
        if(logic.getCurrentQuestion()<10){
            showNextQuestion();
        }
        else{
            //quit the quiz -> K.B. fragen
            Toast.makeText(getApplicationContext(), "10 Questions are asked. Quit.", Toast.LENGTH_SHORT).show();
        }
    }
    /**
     * all buttons are blocked
     * this happens, after one answer is chosen
     */
    public void blockButtons(){
        btnAnswerA.setActivated(false);
        btnAnswerB.setActivated(false);
        btnAnswerC.setActivated(false);
        btnAnswerD.setActivated(false);
    }
    
    
    /**
     * the next question and the new answers are shown and
     * the buttons are enabled
     */
    public void showNextQuestion(){
        logic.resetTimer();
        /*
        btnAnswerA.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
        btnAnswerB.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
        btnAnswerC.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
        btnAnswerD.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
        */
        Question q = logic.nextQuestion();
        
        tvQuestion.setText(q.text);
        btnAnswerA.setText(q.answerA);
        btnAnswerB.setText(q.answerB);
        btnAnswerC.setText(q.answerC);
        btnAnswerD.setText(q.answerD);
        
        btnAnswerA.setActivated(true);
        btnAnswerB.setActivated(true);
        btnAnswerC.setActivated(true);
        btnAnswerD.setActivated(true);
    }
    
    public void wait(int timeMillis, Callback c){
        try{
            Thread.sleep(timeMillis);
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
        c.callback();
    }
    
    private void setAnswersDefault(){
        Toast.makeText(this, "All Buttons on default.", Toast.LENGTH_SHORT).show();
        btnAnswerA.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
        btnAnswerB.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
        btnAnswerC.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
        btnAnswerD.setBackgroundColor(this.getResources().getColor(R.color.answerDefault));
    }
    
    /**
     * Highlights the chosen answer. Green if right, red otherwise.
     * @param correct is true, if the answer has been correct, otherwise it is false
     * @param chosenAnswer Guess 3 times.
     */
    public void highlight(boolean correct, Answer chosenAnswer) {
        
        if(chosenAnswer == Answer.A){
            if(correct){
                btnAnswerA.setBackgroundColor(this.getResources().getColor(R.color.answerCorrect));
                Log.i("backgroundColor", "Button A: "+btnAnswerA.toString());
                Toast.makeText(getApplicationContext(), "A GREEN", Toast.LENGTH_SHORT).show();
            
            }
            else{
                btnAnswerA.setBackgroundColor(this.getResources().getColor(R.color.answerWrong));
                Toast.makeText(getApplicationContext(), "A RED", Toast.LENGTH_SHORT).show();
            }
        }
        else if(chosenAnswer == Answer.B){
            if(correct){
                btnAnswerB.setBackgroundColor(this.getResources().getColor(R.color.answerCorrect));
                Toast.makeText(getApplicationContext(), "B GREEN", Toast.LENGTH_SHORT).show();
            }
            else{
                btnAnswerB.setBackgroundColor(this.getResources().getColor(R.color.answerWrong));
                Toast.makeText(getApplicationContext(), "B RED", Toast.LENGTH_SHORT).show();
            }
        }
        else if(chosenAnswer == Answer.C){
            if(correct){ 
                btnAnswerC.setBackgroundColor(this.getResources().getColor(R.color.answerCorrect));
                Toast.makeText(getApplicationContext(), "C GREEN", Toast.LENGTH_SHORT).show();
            }
            else{
                btnAnswerC.setBackgroundColor(this.getResources().getColor(R.color.answerWrong));
                Toast.makeText(getApplicationContext(), "C RED", Toast.LENGTH_SHORT).show();
            }
        }
        else if(chosenAnswer == Answer.D){
            if(correct){
                btnAnswerD.setBackgroundColor(this.getResources().getColor(R.color.answerCorrect));
                Toast.makeText(getApplicationContext(), "D GREEN", Toast.LENGTH_SHORT).show();
            }
            else{
                btnAnswerD.setBackgroundColor(this.getResources().getColor(R.color.answerWrong));
                Toast.makeText(getApplicationContext(), "D RED", Toast.LENGTH_SHORT).show();
            }    
        }
        wait(1200, new Callback() {
            
            @Override
            public void callback(Object... input) {
                setAnswersDefault();
            }
        });
    }
}

Danke für die Hilfe!
 
Wenn wir jetzt eine Notfall-lösung suchen, könntest du den Thread ja warten lassen (wait).
Dann wird so ziemlich alles warten und android sollte nicht dazwischen funken.
Ist aber keine tolle Lösung.

Vielleicht setzt du einen Timer der alle 1200ms eine Variable überprüft und bei bedarf dann die Farbe vom Button wieder ändert?
Ode gibt es einen besseren und leichteren weg?

Was das färben an sich angeht, Ich habe bisher relativ wenig mit Buttons gemacht, da mein einzige großes Projekt eine App ist, die so ziemlich alle Daten über JSON erhält, heißt ich habe sehr viel mit ListViews gearbeitet. Die Buttons mit der Farbe waren da mehr nur um das ein oder andere Ereignis auszulösen, und da hab ich als "Feedback" bei der Berührung eine andere XML aufgerufen.
 
+1 für die Idee mit dem Timer. Wäre jetzt auch meine Idee gewesen.
Der Thread kommt so wie ich es sehe nicht zur Ausführung. Da sollte noch ein "run();" rein. Aber wie gesagt, ich würde es auch nicht über einen Thread machen. (Vielleicht liege ich hier aber auch falsch. Die Sache mit den Threads (& asynch. Tasks) bin ich selbst gerade am Nacharbeiten)...
Vielleicht erstmal ohne Thread versuchen und wenn das nicht funktioniert markus.tullius oder amfa mal auf den Thread (also dieses Thema im Forum^^) aufmerksam machen und lieb fragen, ob jemand hilft, die kennen sich mit "Threads" deutlich besser aus als ich. :p

Ach so: Die Performance kannst du in deinem Programm noch steigern, indem du eine switch - case Abfrage machst. Gleichzeitig ist das Programm dann auch besser lesbar und ggf sogar unanfälliger gegen Fehler (siehe "default:" bei switch case).
 
Zuletzt bearbeitet:
Den Sinn bei einem Thread hier sehen ich auch nicht so ganz.
Ich nutze eigentlich nur Threads und (async) Tasks wenn ich auf Daten warten muss, aber nicht um eine Aktion nach einer bestimmten Zeit auszuführen.

Ich denke also das der Timer hier voll eine elegante Lösung wäre ;)
 
raptus93 schrieb:
Android scheint der Meinung zu sein, dass es sich dann garnicht lohnt zu switchen, und tut es einfach nicht.

Android switcht die schon, nur vermutlich nicht so (bzw dann), wie du es erwartest.

Ich vermute, es wird momentan in etwa so ablaufen:
  1. du gibtst den Befehl, den Hintergrund zu ändern
  2. noch bevor der Hintergrund geändert hat, lässt du den Haupt-Thread schlafen (was man nie machen sollte)
  3. sobald das Sleep fertig ist, wird der Hintergrund gewechselt und gleich danach wieder zurückgesetzt

Du gehst davon aus, dass die Hintergrundfarbe bereits gewechselt hat, wenn du im Code die nächste Zeile erreichst. Es gibt aber durchaus auch Code, der parallel läuft.

Ohne es mit Sicherheit zu wissen, nehme ich an, dass das Laden deiner Farbe aus den Resourcen asynchron geschieht und deshalb während dem Laden dein Code weiterläuft. Das führt dann dazu, dass der Haupt-Thread bereits die sleep-Anweisung erreicht hat und deshalb nicht den Button neu zeichen kann.

Du musst also das Thread.sleep loswerden. Wie joshua und ui_3k1 bereits erwähnt haben, würde ich hier mit einem Timer arbeiten. Der läuft auch asynchron und blockt deshalb deinen Haupt-Thread nicht.
 
Denke das ist die richtige Lösung. Thread.sleep() gehört nicht in den MainThread. Du solltest ein Thread benutzen. Am einfachsten sollte ein Timer sein.
 
Danke, ich teste es heute mal aus..!
 
Zurück
Oben Unten