1. Nimm jetzt an unserem Uhans - 3. ADVENT - Gewinnspiel teil - Alle Informationen findest Du hier!

ListView - Backgrounds / Listener - Probleme

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von Tom299, 06.09.2011.

  1. Tom299, 06.09.2011 #1
    Tom299

    Tom299 Threadstarter Android-Experte

    Beiträge:
    602
    Erhaltene Danke:
    120
    Registriert seit:
    31.08.2011
    Hallo zusammen,

    ich hab in meiner Activity eine ListView mit einem Listener, um das selektierte Item abzufragen (Check-Boxen hab ich keine mehr in meiner Zeile drin, d.h. das Event kommt einwandfrei erst mal an und mein Toast wird angezeigt beim Klick):

    Code:
            itemsAdapter = new DBItemArrayAdapter(this, R.layout.table_item_new, dbItems);
            listView.setAdapter(itemsAdapter);
    
            listView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView av, View v, int index, long arg3) {
                    //System.out.println("ItemClicked");
                    selectedDBItem = dbItems.get(index);
                    if (selectedDBItem != null) {
                        Toast itemToast = Toast.makeText(getApplicationContext(), selectedDBItem.getName() + " " + selectedDBItem.getVorname(), Toast.LENGTH_SHORT);
                        itemToast.show();
                    }
                }
            });
            
            layout.addView(listView);
    
    Dadurch hat man erst mal ein "Standardlayout mit Standardfarben", wobei hier alle Zeilen die gleiche Farbe haben und die selektierte Zeile wird orange hervorgehoben. Soweit so gut.

    Nun will ich aber, daß meine Zeilen abwechselnde Farben haben. Also hab ich in meinem Adapter folgendes eingebaut:

    Code:
            final TableRow rowItem = (TableRow)dbItemsView.findViewById(R.id.item_row);
            if (position % 2 == 0) {
                //rowItem.setBackgroundColor(Color.DKGRAY);
                rowItem.setBackgroundColor(colorEven);
            }
            else {
                //rowItem.setBackgroundColor(Color.GRAY);
                rowItem.setBackgroundColor(colorOdd);
            }
    
    Die Zeilen werden zwar nun schön abwechselnd eingefärbt, allerdings wird nun die selektierte Zeile nicht mehr farblich hervorgehoben (keine Standard-Orange-Farbe mehr).

    Ok dachte ich mir, dann muß ich das wohl auch selbst übernehmen, also hab ich einen OnTouch-Listener implementiert:
    Code:
            rowItem.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
                        rowItem.setBackgroundColor(Color.YELLOW);
                        return true;
                    }
                    else if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (position % 2 == 0) {
                            //rowItem.setBackgroundColor(Color.DKGRAY);
                            rowItem.setBackgroundColor(colorEven);
                        }
                        else {
                            //rowItem.setBackgroundColor(Color.GRAY);
                            rowItem.setBackgroundColor(colorOdd);
                        }                    
                        return true;
                    }
                    else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
                        if (position % 2 == 0) {
                            //rowItem.setBackgroundColor(Color.DKGRAY);
                            rowItem.setBackgroundColor(colorEven);
                        }
                        else {
                            //rowItem.setBackgroundColor(Color.GRAY);
                            rowItem.setBackgroundColor(colorOdd);
                        }                    
                        return true;
                    }
                                    
                    return false;
                }
            });
    
    Damit wird nun meine selektierte Zeile wieder farblich hervorgehoben bzw. beim deselektieren wieder die alte Zeilenfarbe genommen.

    Doch nun hab ich das Problem, daß mein OnItemClickListener der ListView nicht mehr funktioniert, da das TouchEvent wohl den Click konsumiert.

    Wie kann ich nun das Event weiterreichen, damit der OnItemClickListener weiterhin funktioniert oder wie macht man es richtig in Android?

    Mein erster Versuch war, das return-Ergebnis von true auf false im OnTouch-Listener zu setzen. Das scheint prinzipiell zu funktionieren, aber dann funktioniert das deselektieren der Zeile nicht mehr. Also irgendwo bekomm ich momentan immer nen Folgefehler bei meiner Vorgehensweise ...


    Gruß,
    Tom
     
  2. sixi, 06.09.2011 #2
    sixi

    sixi Erfahrener Benutzer

    Beiträge:
    237
    Erhaltene Danke:
    64
    Registriert seit:
    20.01.2009
    Hallo Tom,

    statt die Farbe manuell zu ändern macht es Sinn 'nen StateListDrawable oder eine ColorStateListResourcezu verwenden, dann kannst du dir das überschreiben der onTouch-Methode - und den verbundenen Problemen - sparen ;)
     
    Tom299 bedankt sich.
  3. Tom299, 06.09.2011 #3
    Tom299

    Tom299 Threadstarter Android-Experte

    Beiträge:
    602
    Erhaltene Danke:
    120
    Registriert seit:
    31.08.2011
    Hallo sixi,

    erst mal danke für die Tips. Ich hab mir deine Vorschläge mal angesehen und ein bischen damit rumgespielt. Aber ich glaube, im Endeffekt hilft es mir hier nicht weiter, da ich ja nur eine default-Farbe angeben kann und halt z.b. die pressed-Color. Wenn ich aber 2 unterschiedliche Hintergrundfarben in meiner Liste benutze (gerade und ungerade zeile) dann bekomm ich es damit ja auch nicht mehr richtig zurückgesetzt. Oder hab ich evtl. nen Denkfehler hier? ;-)

    Allerdings frage ich mich gerade, ob es evtl. sinnvoller wäre, eine eigene ListView zu schreiben, die sich um die Farben kümmert, anstatt die Farben im Adapter zu setzen. Der Adapter sollte vermutlich eher nur für das Mapping der Daten zu den GUI-Elementen benutzt werden, oder?

    Ich werde mir mal ne eigene ListView ableiten und schauen, ob ich hier was drehen kann :)
     
  4. sixi, 06.09.2011 #4
    sixi

    sixi Erfahrener Benutzer

    Beiträge:
    237
    Erhaltene Danke:
    64
    Registriert seit:
    20.01.2009
    Da brauchste am ListView nichts zu ändern.
    In deinem Adapter in der getView-Methode bauste den Teil ein, den du schon hast und änderst ihn ein bisschen:
    Code:
            if (position % 2 == 0) {
                v.setBackgroundResource(DEINE_SELECTOR_RESOURCE_GERADE);
            }
            else {
                v.setBackgroundResource(DEINE_SELECTOR_RESOURCE_UNGERADE);
            }
    
    ausgehend davon, dass dein View (der Parameter von getView bzw. wenn du ihn neu verwendest etc.) "v" heißt.
     
    Tom299 bedankt sich.
  5. Tom299, 06.09.2011 #5
    Tom299

    Tom299 Threadstarter Android-Experte

    Beiträge:
    602
    Erhaltene Danke:
    120
    Registriert seit:
    31.08.2011
    Ich habe jetzt mal 2 resource-files angelegt:

    even_color_row.xml
    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <selector
          xmlns:android="http://schemas.android.com/apk/res/android">
        <item 
            android:state_pressed="true"
            android:color="@color/table_row_highlight_color">
        </item>
        <item 
            android:color="@color/table_row_color_even">
        </item>
    </selector>
    
    odd_color_row.xml
    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <selector
          xmlns:android="http://schemas.android.com/apk/res/android">
        <item 
            android:state_pressed="true" 
            android:color="@color/table_row_highlight_color">
        </item>
        <item 
            android:color="@color/table_row_color_odd">
        </item>    
    </selector>
    
    und in meinem Adapter dann eingebunden
    Code:
            final TableRow rowItem = (TableRow)dbItemsView.findViewById(R.id.item_row);
            if (position % 2 == 0) {
                //rowItem.setBackgroundColor(colorEven);
                rowItem.setBackgroundResource(R.color.even_color_row);
            }
            else {
                //rowItem.setBackgroundColor(colorOdd);
                rowItem.setBackgroundResource(R.color.odd_color_row);
            }
    
    soweit sollte es doch richtig sein, oder?

    aber wenn ich das programm nun starte wird es direkt wieder abgebrochen und ich bekomm den Fehler:
    Code:
    ERROR/AndroidRuntime(211): Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #7: <item> tag requires a 'drawable' attribute or child tag defining a drawable
    
    ich hab schon geschaut, ob ich innerhalb des Item-Tags ein child- oder drawable-attribut finde, aber leider nichts :confused:
     
  6. Tom299, 06.09.2011 #6
    Tom299

    Tom299 Threadstarter Android-Experte

    Beiträge:
    602
    Erhaltene Danke:
    120
    Registriert seit:
    31.08.2011
    ah, ich habs doch noch hinbekommen, pünktlich zum feierabend :)

    ich mußte eine drawable resource anlegen:


    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <selector
          xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true"
              android:drawable="@color/table_row_highlight_color" /> <!-- pressed -->
        <item android:drawable="@color/table_row_color_even" /> <!-- default -->    
    </selector>
    

    und dann in meinem adapter angeben
    Code:
    rowItem.setBackgroundResource(R.drawable.drawable_even_color);
    
    jetzt klappts endlich :w00t00:


    vielen dank sixi für die tips :)
     

Diese Seite empfehlen