Verwendung von ArrayAdapter <myClass>

129
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);

Klasse: MyClass

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

Ich habe row.xml in Layouts erstellt, weiß aber nicht, wie ich mit ArrayAdapter sowohl reason als auch long_val in der ListView anzeigen kann.

Sumit M Asok
quelle

Antworten:

155

Implementieren Sie einen benutzerdefinierten Adapter für Ihre Klasse:

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;
    }
}

Für diejenigen, die mit dem Android-Framework nicht sehr vertraut sind, wird dies hier ausführlicher erläutert: https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView .

Nikola Smiljanić
quelle
2
Entschuldigung, MyClass item = items.get (position) löst den Fehler und stimmt nicht mit den Variablen von mir überein.
Sumit M Asok
1
Ich habe das Elementfeld aus dem obigen Code entfernt, da es leicht zu Fehlern führen kann - zum Beispiel, wenn jemand die interne Liste der Elemente mit adapter.clear () oder adapter.add (...)
ändert
1
Bin ich richtig in der Annahme textViewResourceId, dass oben nicht verwendet wird?
Gerrytan
8
Woher kam viewHolder?
Gerry
2
Was ist R.layout.listview_association? Ist das Ihr benutzerdefiniertes Layout? Kann ich es durch android.R.layout.simple_list_item_1 ersetzen?
Donato
76

Sie können toString()MyClass einfach eine Methode hinzufügen : http://developer.android.com/reference/android/widget/ArrayAdapter.html :

Obwohl auf die Textansicht verwiesen wird, wird sie mit dem toString () jedes Objekts im Array gefüllt. Sie können Listen oder Arrays von benutzerdefinierten Objekten hinzufügen. Überschreiben Sie die toString () -Methode Ihrer Objekte, um zu bestimmen, welcher Text für das Element in der Liste angezeigt wird.

class MyClass {

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

quelle
20
Obwohl dies die einfachste Lösung ist, ist dies (IMHO) keine sehr gute Idee. Drei Gründe: Wenn Sie jemals eine Lokalisierung benötigen, müssen Sie eine Umgestaltung vornehmen. Dies funktioniert nur, wenn Sie 1 Adapter haben. Wenn Sie 2 verschiedene Adapter für haben MyClass, müssen Sie umgestalten. Schließlich ist es im Allgemeinen eine schlechte Idee, die Präsentationslogik mit Ihren Modellen zu verknüpfen. Modelle sollten nicht wissen, wie sie dem Benutzer präsentiert werden.
fernandohur
2
Um einige der @ fernandohur-Probleme zu lösen, können Sie einfach eine dedizierte Ansichtsklasse für den ArrayAdapter erstellen. Für eine Modellklasse vom Typ MyClassmüssen Sie also eine dedizierte Klasse hinzufügen, MyClassViewdie das zugrunde liegende Modell umschließt (und die toString( )Implementierung bereitstellt
wal
Diese Antwort stammt aus dem Jahr 2011 und ich stimme @fernandohur zu - es gibt jetzt bessere Möglichkeiten, damit umzugehen.
Ich denke, dies ist eine gute Antwort, da in vielen Fällen jede Klasse ein Attribut hat, das den Namen des Objekts darstellt.
Jhon Fredy Trujillo Ortega
Dies sollte die akzeptierte Antwort sein. Das Überschreiben eines Adapters nur zum Binden des gedruckten Namens ist eine schlechte Codierung.
L. Grillo
22

Ich denke, das ist der beste Ansatz. Die Verwendung der generischen ArrayAdapter-Klasse und die Erweiterung Ihres eigenen Objektadapters ist wie folgt:

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);
    }
  }
}

und hier dein Adapter (Beispiel):

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());
  }

}

und schließlich, wie man es initialisiert:

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

Ich habe einen Gist mit anpassbarem ArrayVadapter für die Schwerkraft des TextView-Layouts erstellt:

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

cesards
quelle
1
Ihr Code hat mir sehr gut gefallen, aber ich habe eine Weile gebraucht, um herauszufinden, warum er mit android.content.res.Resources $ NotFoundException: Resource ID # 0x0 abgestürzt ist. Sie haben in Ihrem generischen Adapteraufruf super (.., 0, ..), wobei 0 tatsächlich eine Layoutressource ist, die nicht vorhanden ist, daher muss sie in etwas anderes geändert werden. Außerdem lautet Ihr Kern 404
Ev0oD
Am Ende habe ich viel geändert - das Layout des Dropdown-Menüs war anders als das Layout des angezeigten Elements. Der drawText wurde nur im Spinner-Header aufgerufen, nicht in den angeklickten Elementen.
Ev0oD
Dies sollte als generischer Adapter gültig sein. Könnten Sie das Problem lösen?
Cesards
Ja, ich habe es geschafft. Mir wurde klar, dass Sie eine Lösung für etwas anderes als das bieten, was ich wollte, aber ich konnte Ihren Code als Ausgangspunkt verwenden und Änderungen so vornehmen, dass sie für mich das taten, was ich wollte. Danke für diesen Code.
Ev0oD
Dies sollte standardmäßig bereitgestellt werden.
Goddard
6

Unterklassifizieren Sie den ArrayAdapter und überschreiben Sie die Methode getView () , um Ihre eigene Ansicht zurückzugeben, die den Inhalt enthält, den Sie anzeigen möchten.

Klarth
quelle
5

Hier ist ein kurzes und schmutziges Beispiel für die Verwendung eines ArrayAdapters, wenn Sie sich nicht mit der Erweiterung der Mutterklasse beschäftigen möchten:

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
quelle