Tło elementu ListView za pomocą selektora niestandardowego


98

Czy za pomocą selektora listy można zastosować niestandardowe tło do każdego elementu widoku listy?

W selektor określa domyślny @android:color/transparentdla state_focused="false"sprawy, ale zmiana ta w jakimś niestandardowym rozciągliwej nie wpływa na elementy, które nie zostały wybrane. Romain Guy wydaje się sugerować w tej odpowiedzi, że jest to możliwe.

Obecnie osiągam ten sam efekt, używając niestandardowego tła w każdym widoku i ukrywając je, gdy element jest zaznaczony / wyostrzony / cokolwiek, aby selektor był pokazany, ale byłoby bardziej elegancko, gdyby to wszystko było zdefiniowane w jednym miejscu.

Dla porównania, oto selektor, którego używam, aby spróbować uruchomić to:

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="false"
        android:drawable="@drawable/list_item_gradient" />

    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
    <item android:state_focused="true" android:state_enabled="false"
        android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_disabled" />
    <item android:state_focused="true" android:state_enabled="false"
        android:drawable="@drawable/list_selector_background_disabled" />

    <item android:state_focused="true" android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_transition" />
    <item android:state_focused="false" android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_transition" />

    <item android:state_focused="true"
        android:drawable="@drawable/list_selector_background_focus" />

</selector>

A tak ustawiam selektor:

<ListView
    android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:listSelector="@drawable/list_selector_background" />    

Z góry dziękuję za pomoc!

Odpowiedzi:


128

Sam byłem tym sfrustrowany i ostatecznie go rozwiązałem. Jak zasugerował Romain Guy, istnieje inny stan, z "android:state_selected"którego musisz skorzystać. Użyj stanu, który można narysować jako tło elementu listy, i użyj innego stanu, który można narysować dla listSelectorswojej listy:

list_row_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:background="@drawable/listitem_background"
    >
...
</LinearLayout>

listitem_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@color/android:transparent" />
    <item android:drawable="@drawable/listitem_normal" />
</selector>

layout.xml, który zawiera ListView:

...
<ListView 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:listSelector="@drawable/listitem_selector"
   />
...

listitem_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/listitem_pressed" />
    <item android:state_focused="true" android:drawable="@drawable/listitem_selected" />
</selector>

1
Dzięki za szczegółową odpowiedź. Jak wspomniałem w swoim pytaniu, właśnie to robię w tej chwili i działa całkiem dobrze.
shilgapira

Niestety nadal mam problemy z dostosowywaniem widoku listy. Opublikowałem tutaj moje konkretne problemy: stackoverflow.com/questions/5426385/… ; Byłbym wdzięczny za wszelkie uwagi.
LostNomad311

Nie działa, gdy używasz 9-łatek do rysowania z wypełnieniem jako tłem. Znalazłem ostateczne rozwiązanie, myślę, że zobacz moją odpowiedź
Michał K

Działa to w przypadku post-ICS, ale w przypadku Gingerbread cała lista jest pokolorowana za pomocą tłoczonych lub wybranych rysunków.
gunar

Czy jest jakieś rozwiązanie dla pre-ICS?
Lonli-Lokli

78

Rozwiązanie dglmtn nie działa, gdy masz 9 łatek do rysowania z wypełnieniem jako tłem. Dziwne rzeczy się zdarzają, nawet nie chcę o tym rozmawiać, jak masz taki problem to je znasz.

Teraz, jeśli chcesz mieć widok listy z różnymi stanami i elementami do rysowania z 9 łatkami (myślę, że działałby z dowolnymi rysunkami i kolorami), musisz zrobić 2 rzeczy:

  1. Ustaw selektor dla elementów na liście.
  2. Pozbądź się domyślnego selektora listy.

Najpierw ustaw row_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_enabled="true" 
     android:state_pressed="true" android:drawable="@drawable/list_item_bg_pressed" />
    <item android:state_enabled="true"
     android:state_focused="true" android:drawable="@drawable/list_item_bg_focused" />
    <item android:state_enabled="true"
     android:state_selected="true" android:drawable="@drawable/list_item_bg_focused" />
    <item
     android:drawable="@drawable/list_item_bg_normal" />
</selector>

Nie zapomnij o android:state_selected. Działa jak android:state_focusedw przypadku listy, ale jest stosowany do elementu listy.

Teraz zastosuj selektor do elementów (row.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/row_selector"
>
...
</RelativeLayout>

Utwórz przezroczysty selektor dla listy:

<ListView
    android:id="@+id/android:list"
    ...
    android:listSelector="@android:color/transparent"
    />

To powinno wystarczyć.


1
+1, nie widziałem wcześniej Twojej odpowiedzi, natknąłem się na ten sam wynik, robiąc to samodzielnie. Ale dziękuję za wspomnienie o rysunkach z 9 łatkami, jestem pewien, że mogą się przydać w moich przyszłych implementacjach. To powinna być najlepsza odpowiedź, ponieważ ta metoda jest czystsza i łatwa w utrzymaniu.
IsaacCisneros

28
Przykro mi, ale to są rzeczy, które czasami sprawiają, że myślę, dlaczego te cholerne interfejsy API muszą być takie gówniane. Android wciąż ma wiele do przejścia. Takie podstawowe rzeczy nie powinny być takie PITA.
Gubatron,

2
+1 Dziękuję, dziękuję, dziękuję. Przeskakiwanie przez wszystkie te obręcze, aby osiągnąć coś tak podstawowego. Wszystkie te stany są tak bardzo zagmatwane.
Moritz

3
Zamiast android: listSelector = "@ drawable / list_selector" po prostu napisz android: listSelector = "@ android: color / transparent". Nie ma potrzeby stosowania dodatkowego list_selector.xml.
Sofi Software LLC

1
Prawidłowo, nieniszczący selektor listy może być po prostu @android: color / transparent zamiast własnego selektora XML. Po prostu spróbowałem. Rzecz, która nie działa, to @ null, co mnie zaskakuje, ponieważ powinno to brzmieć: "brak selektora listy", a ponieważ selektor listy jest rysowany za elementem, nic nie powinno być rysowane. Ale to nie działa, domyślny selektor jest wtedy ...
Zordid

17

Nigdy, przenigdy nie używaj „koloru tła” dla wierszy widoku listy ...

to zablokuje każdą akcję selektora (to był mój problem!)

powodzenia!


3
To nie jest prawda. Po prostu użyj selektora jako tła, a nie statycznego koloru lub rysowania
Michał K

w zamierzeniu miało to oznaczać „kolor tła”. całkowicie zaakceptuj swoje słowa.
cV2,

Dotarłem tutaj, ponieważ teraz potrzebuję selektora, którego użyłem setBackgroundColorz „kolorem”. Ech ... Użyj setBackgroundlub setBackgroundDrawablezgodnie z wersją API z selektorem.
EpicPandaForce

5

Artykuł „Dlaczego moja lista jest czarna? Optymalizacja systemu Android” na blogu dla programistów Androida zawiera dokładne wyjaśnienie, dlaczego podczas przewijania tło listy zmienia kolor na czarny. Prosta odpowiedź: ustaw cacheColorHint na liście jako przezroczystą (# 00000000).


1
Wzorowa prostota, ale działa bardzo dobrze. Dzięki za Romain Guy ... <ListView ... android: cacheColorHint = "# 00000000"> </ListView> To wszystko!
Eric JOYÉ

Nie dziękuj Romainowi Guyowi. On jest częścią problemu. W takim systemie operacyjnym nie powinno być tak wielu „ukrytych sztuczek” ani innych hacków. Mimo że uwielbiam Androida, w porównaniu z innymi pakietami SDK (nawet nowszymi / mniej dojrzałymi!) Jest to spora kupa bzdur.
StackOverflowed

5

Wystarczy, jeśli włożysz list_row_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/listitem_background">... </LinearLayout>

listitem_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/dark" android:state_pressed="true" />
    <item android:drawable="@color/dark" android:state_focused="true" />
    <item android:drawable="@android:color/white" />
</selector>

2
niesamowity ... najprostszy przykład
Shihab Uddin

1
A także uczyń selektor widoku listy przezroczystym
Sayka

4

zamiast:

android:drawable="@color/transparent" 

pisać

android:drawable="@android:color/transparent"

4

Możesz napisać motyw:

<pre>

    android:name=".List10" android:theme="@style/Theme"

theme.xml

<style name="Theme" parent="android:Theme">
        <item name="android:listViewStyle">@style/MyListView</item>
</style>

style.xml

 <style name="MyListView" parent="@android:style/Widget.ListView">
<item name="android:listSelector">@drawable/my_selector</item>

my_selector to Twój niestandardowy selektor. Przykro mi, że nie wiem, jak napisać mój kod


Dzięki za pomoc, ale to nie pomaga bezpośrednio w ustawianiu domyślnego tła listitem za pomocą selektora.
shilgapira

2

Nie jestem pewien, jak osiągnąć zamierzony efekt za pomocą samego selektora - w końcu z definicji jest jeden selektor dla całej listy.

Możesz jednak kontrolować zmiany zaznaczenia i rysować, co chcesz. W tym przykładowym projekcie ustawiam przezroczystość selektora i rysuję pasek na wybranym elemencie.


Rzeczywiście, absolutnie sensowne jest, aby istniał tylko jeden selektor. Wydaje mi się, że jestem (lub byłem) trochę zdezorientowany istnieniem <item android:state_focused="false" android:drawable="@android:color/transparent" />klauzuli w selektorze domyślnym.
shilgapira

Mark, bawię się (mam ten sam problem co Gil). Wypróbowałem twoje rozwiązanie, jest to tylko częściowe tylko dla track ball, noneSeelected jest wywoływane, gdy dotykasz przedmiotów za pomocą dotyku, a onItemClicked jest uruchamiany, jeśli chcesz czegoś takiego, najprawdopodobniej musisz śledzić wybrane i wciśnięte pozycje wewnątrz ListView i narysować to, czego potrzebujesz w samym elemencie (uczyń go niestandardowym widokiem) oraz w dispatchDraw w ListView.
codeScriber

@codeScriber: "noneSeelected jest wywoływane, gdy dotykasz elementów za pomocą tylko dotyku, a onItemClicked jest uruchamiany" - jest to całkowicie normalne zachowanie, ponieważ dotyk nie ma nic wspólnego z zaznaczaniem.
CommonsWare

2

Zawsze używam tej samej metody i działa zawsze i wszędzie: po prostu używam takiego selektora

<item android:state_activated="true"  android:color="@color/your_selected_color" />
<item android:state_pressed="true" android:color="@color/your_pressed_color" />
<item android:color="@color/your_normal_color"></item>

i ustaw w ListView (BARDZO WAŻNE, ABY TO DZIAŁAŁO) atrybut

android:choiceMode="singleChoice"

dla textColor po prostu umieść w folderze kolorów (WAŻNE, nie do rysowania!) selektor taki jak ten

<item android:state_activated="true"  android:color="@color/your_selected_textColor" />
<item android:state_pressed="true" android:color="@color/your_pressed_textColor" />
<item android:color="@color/your_normal_textColor"></item>

to przykładowy szablon wiersza

<ImageView
    android:id="@+skinMenu/lblIcon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:src="@drawable/menu_catalog" />

<TextView
    android:id="@+skinMenu/lblTitle"
    style="@style/superlabelStyle"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_marginLeft="20dp"
    android:gravity="center_vertical"
    android:text="test menu testo"
    android:textColor="@color/menu_textcolor_selector"
    android:textSize="20dp"
    android:textStyle="bold" />

wszystko pokazuje pracę bez żmudnych obejść. Mam nadzieję, że to pomoże


-3

Zespół FrostWire tutaj.

Wszystkie badziewne api selektora nie działają zgodnie z oczekiwaniami. Po wypróbowaniu wszystkich rozwiązań przedstawionych w tym wątku do niczego, po prostu rozwiązaliśmy problem w momencie zawyżania elementu ListView.

  1. Upewnij się, że Twój przedmiot zachowuje swój stan, zrobiliśmy to jako zmienna składowa elementu MenuItem (wybrana wartość logiczna)

  2. Kiedy nadmuchujesz, zapytaj, czy element bazowy jest wybrany, jeśli tak, po prostu ustaw żądany zasób jako tło (czy to 9 łatka, czy cokolwiek). Upewnij się, że twój adapter jest tego świadomy i że wywołuje notifyDataChanged (), gdy coś zostało wybrane.

        @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View rowView = convertView;
        if (rowView == null) {
            LayoutInflater inflater = act.getLayoutInflater();
            rowView = inflater.inflate(R.layout.slidemenu_listitem, null);
            MenuItemHolder viewHolder = new MenuItemHolder();
            viewHolder.label = (TextView) rowView.findViewById(R.id.slidemenu_item_label);
            viewHolder.icon = (ImageView) rowView.findViewById(R.id.slidemenu_item_icon);
            rowView.setTag(viewHolder);
        }
    
        MenuItemHolder holder = (MenuItemHolder) rowView.getTag();
        String s = items[position].label;
        holder.label.setText(s);
        holder.icon.setImageDrawable(items[position].icon);
    
        //Here comes the magic
        rowView.setSelected(items[position].selected);
    
        rowView.setBackgroundResource((rowView.isSelected()) ? R.drawable.slidemenu_item_background_selected : R.drawable.slidemenu_item_background);
    
        return rowView;
    }

Byłoby naprawdę fajnie, gdyby selektory faktycznie działały, w teorii to ładne i eleganckie rozwiązanie, ale wygląda na to, że jest zepsute. POCAŁUNEK.


Chcę wypróbować to rozwiązanie, czy mógłbyś podać bardziej szczegółowe wyjaśnienie lub kompletne rozwiązanie? Dzięki
Andrew Lam
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.