Jak używać ArrayAdapter <myClass>


130
ArrayList<MyClass> myList = new ArrayList<MyClass>();

ListView listView = (ListView) findViewById(R.id.list);

ArrayAdapter<MyClass> adapter = new ArrayAdapter<MyClass>(this, R.layout.row,
    to, myList.);
listView.setAdapter(adapter);

Klasa: MyClass

class MyClass {
    public String reason;
    public long long_val;
}

Utworzyłem row.xml w układach, ale nie wiem, jak pokazać zarówno przyczynę, jak i long_val w ListView przy użyciu ArrayAdapter.

Odpowiedzi:


156

Zaimplementuj niestandardowy adapter dla swojej klasy:

public class MyClassAdapter extends ArrayAdapter<MyClass> {

    private static class ViewHolder {
        private TextView itemView;
    }

    public MyClassAdapter(Context context, int textViewResourceId, ArrayList<MyClass> items) {
        super(context, textViewResourceId, items);
    }

    public View getView(int position, View convertView, ViewGroup parent) {

        if (convertView == null) {
            convertView = LayoutInflater.from(this.getContext())
            .inflate(R.layout.listview_association, parent, false);

            viewHolder = new ViewHolder();
            viewHolder.itemView = (TextView) convertView.findViewById(R.id.ItemView);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        MyClass item = getItem(position);
        if (item!= null) {
            // My layout has only one TextView
                // do whatever you want with your string and long
            viewHolder.itemView.setText(String.format("%s %d", item.reason, item.long_val));
        }

        return convertView;
    }
}

Dla osób niezbyt zaznajomionych z platformą Android wyjaśniono to bardziej szczegółowo tutaj: https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView .


2
Przepraszamy, pozycja MyClass = items.get (pozycja) rozwiązuje błąd, niedopasowanie zmiennych przeze mnie.
— Sumit M Asok

1
Usunąłem pole items z powyższego kodu, bo łatwo może to doprowadzić do błędów - np. Jeśli ktoś zmieni wewnętrzną listę pozycji za pomocą adapter.clear () lub adapter.add (...)
— prostynick

1
Czy mam rację zakładając, że textViewResourceIdnie zostało użyte powyżej?
— gerrytan

8
skąd się wziął viewHolder?
— Gerry

2
Co to jest R.layout.listview_association? Czy to twój niestandardowy układ? Czy mogę zamienić go na android.R.layout.simple_list_item_1?
— Donato,

77

Możesz po prostu dodać toString()metodę do MyClass, na http://developer.android.com/reference/android/widget/ArrayAdapter.html :

Jednak odwołanie do TextView zostanie wypełnione metodą toString () każdego obiektu w tablicy. Możesz dodawać listy lub tablice obiektów niestandardowych. Zastąp metodę toString () obiektów, aby określić, jaki tekst będzie wyświetlany dla elementu na liście.

class MyClass {

 @Override
 public String toString() {
  return "Hello, world.";
 }
}

20
Chociaż jest to najprostsze rozwiązanie, to (IMHO) nie jest zbyt dobrym pomysłem. Trzy powody: jeśli kiedykolwiek będziesz potrzebować lokalizacji, będziesz musiał dokonać refaktoryzacji. Działa to tylko wtedy, gdy masz 1 adapter, jeśli masz 2 różne adaptery MyClass, będziesz musiał refaktoryzować. Wreszcie, generalnie złym pomysłem jest powiązanie logiki prezentacji z modelami. Modele nie powinny być świadome tego, w jaki sposób są prezentowane użytkownikowi.
— fernandohur

2
aby rozwiązać niektóre z problemów @fernandohur, możesz po prostu utworzyć dedykowaną klasę widoku dla ArrayAdapter ... więc klasa modelu MyClasswymagałaby dodania dedykowanej klasy o nazwie, MyClassViewktóra otacza model bazowy (i zapewnia toString( )implementację
— wal

Ta odpowiedź pochodzi z 2011 roku i zgadzam się z @fernandohur - są teraz lepsze sposoby radzenia sobie z tym.

Myślę, że jest to dobra odpowiedź, ponieważ w wielu przypadkach każda klasa ma atrybut niż nazwa obiektu.
— Jhon Fredy Trujillo Ortega

To powinna być akceptowana odpowiedź. Zastępowanie adaptera tylko w celu powiązania wydrukowanej nazwy jest złym kodowaniem.
— L.Grillo

22

Myślę, że to najlepsze podejście. Użycie ogólnej klasy ArrayAdapter i rozszerzenie własnego adaptera Object jest tak proste, jak poniżej:

public abstract class GenericArrayAdapter<T> extends ArrayAdapter<T> {

  // Vars
  private LayoutInflater mInflater;

  public GenericArrayAdapter(Context context, ArrayList<T> objects) {
    super(context, 0, objects);
    init(context);
  }

  // Headers
  public abstract void drawText(TextView textView, T object);

  private void init(Context context) {
    this.mInflater = LayoutInflater.from(context);
  }

  @Override public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder vh;
    if (convertView == null) {
      convertView = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
      vh = new ViewHolder(convertView);
      convertView.setTag(vh);
    } else {
      vh = (ViewHolder) convertView.getTag();
    }

    drawText(vh.textView, getItem(position));

    return convertView;
  }

  static class ViewHolder {

    TextView textView;

    private ViewHolder(View rootView) {
      textView = (TextView) rootView.findViewById(android.R.id.text1);
    }
  }
}

a tutaj twój adapter (przykład):

public class SizeArrayAdapter extends GenericArrayAdapter<Size> {

  public SizeArrayAdapter(Context context, ArrayList<Size> objects) {
    super(context, objects);
  }

  @Override public void drawText(TextView textView, Size object) {
    textView.setText(object.getName());
  }

}

i wreszcie, jak go zainicjalizować:

ArrayList<Size> sizes = getArguments().getParcelableArrayList(Constants.ARG_PRODUCT_SIZES);
SizeArrayAdapter sizeArrayAdapter = new SizeArrayAdapter(getActivity(), sizes);
listView.setAdapter(sizeArrayAdapter);

Stworzyłem Gist z ArrayAdapter z możliwością dostosowania grawitacji w układzie TextView:

https://gist.github.com/m3n0R/8822803


1
Bardzo podobał mi się twój kod, ale zajęło mi trochę czasu, zanim zrozumiałem, dlaczego powodował awarię z android.content.res.Resources $ NotFoundException: Resource ID # 0x0. Masz w swoim ogólnym wywołaniu adaptera super (.., 0, ..), gdzie 0 jest w rzeczywistości zasobem układu, który nie istnieje, więc należy go zmienić na coś innego .. Ponadto, twoja treść to 404
— Ev0oD

W końcu bardzo się zmieniłem - układ menu rozwijanego był inny niż układ pokazanego elementu, drawText był wywoływany tylko na nagłówku spinner, a nie na jego elementach po kliknięciu ...
— Ev0oD

Powinien być prawidłowy jako adapter ogólny. Czy mógłbyś rozwiązać problem?
— cesards

Tak, sprawiłem, że to zadziałało. Zdałem sobie sprawę, że dostarczasz rozwiązanie dla czegoś nieco innego niż to, co chciałem, ale mogłem użyć twojego kodu jako punktu wyjścia i wprowadzić poprawki w sposób, który zrobił dla mnie to, czego chciałem. Dzięki za ten fragment kodu.
— Ev0oD

Powinno to być podane domyślnie.
— Goddard

6

Podklasuj ArrayAdapter i zastąp metodę getView (), aby zwrócić własny widok zawierający zawartość, którą chcesz wyświetlić.


5

Oto szybki i nieprzyjemny przykład użycia ArrayAdapter, jeśli nie chcesz zawracać sobie głowy rozszerzaniem klasy matki:

class MyClass extends Activity {
    private ArrayAdapter<String> mAdapter = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mAdapter = new ArrayAdapter<String>(getApplicationContext(),
            android.R.layout.simple_dropdown_item_1line, android.R.id.text1);

        final ListView list = (ListView) findViewById(R.id.list);
        list.setAdapter(mAdapter);

        //Add Some Items in your list:
        for (int i = 1; i <= 10; i++) {
            mAdapter.add("Item " + i);
        }

        // And if you want selection feedback:
        list.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //Do whatever you want with the selected item
                Log.d(TAG, mAdapter.getItem(position) + " has been selected!");
            }
        });
    }
}
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.