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.

Sumit M Asok
źródło

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 .

Nikola Smiljanić
źródło
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.";
 }
}

źródło
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

cesardy
źródło
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ć.

Klarth
źródło
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!");
            }
        });
    }
}
Francois Dermu
źródło