Die ListView
wird Ansichten recyceln, wie Sie es nach oben und unten scrollen, wenn es ein neues Kind View
zu zeigen benötigt, wird es zuerst sehen, ob es nicht bereits eins (wenn es eines findet es wird es verwenden). Wenn Sie die Kinder eines ListView
wie Sie (in der onListItemClick()
Methode) ändern und dann die Liste scrollen, wird die ListView
schließlich am Ende dieses Kind View
wiederverwenden, das Sie geändert haben, und Sie werden mit bestimmten Ansichten in Position enden, die Sie don 't wollen (wenn Sie weiter scrollen ListView
Sie sehen zufällige Position ändern wegen der View
Recycling).
Eine Möglichkeit, dies zu verhindern, besteht darin, sich an die Positionen zu erinnern, auf die der Benutzer geklickt hat, und im Adapter das Layout dieser bestimmten Zeile zu ändern, jedoch nur für die gewünschte Position. Sie können (in der Klasse ein Feld) jene ids
in einem HashMap
speichern:
private HashMap<Long, Boolean> status = new HashMap<Long, Boolean>();
ich ein HashMap
verwendet, aber Sie können andere Behälter verwenden (im Code unten sehen, warum ich ein HashMap
wählen).Als nächstes werden in der onListItemClick()
Methode werden Sie die geklickt Zeile ändern, sondern speichern auch diese Zeile id
so der Adapter kennt (und Maßnahmen zu ergreifen, so dass Sie nicht mit dem falschen recycelten Ansichten am Ende):
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// check and see if this row id isn't already in the status container,
// if it is then the row is already set, if it isn't we setup the row and put the id
// in the status container so the adapter will know what to do
// with this particular row
if (status.get(id) == null) {
status.put(id, true);
v.getLayoutParams().height = 200;
v.requestLayout();
TextView d = (TextView) v.findViewById(R.id.description);
d.setVisibility(View.VISIBLE);
}
}
dann in verwenden der Adapter den Status Behälter mit dem alle ids
Setup die Zeilen richtig und verhindern, dass das Recycling zu Chaos mit unseren Reihen:
private class CustomAdapter extends CursorAdapter {
private LayoutInflater mInflater;
public CustomAdapter(Context context, Cursor c) {
super(context, c);
mInflater = LayoutInflater.from(context);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView title = (TextView) view.findViewById(R.id.title);
title.setText(cursor.getString(cursor.getColumnIndex("name")));
TextView description = (TextView) view
.findViewById(R.id.description);
description.setText(cursor.getString(cursor
.getColumnIndex("description")));
// get the id for this row from the cursor
long rowId = cursor.getLong(cursor.getColumnIndex("_id"));
// if we don't have this rowId in the status container then we explicitly
// hide the TextView and setup the row to the default
if (status.get(rowId) == null) {
description.setVisibility(View.GONE);
// this is required because you could have a recycled row that has its
// height set to 200 and the description TextView visible
view.setLayoutParams(new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.MATCH_PARENT));
} else {
// if we have the id in the status container then the row was clicked and
// we setup the row with the TextView visible and the height we want
description.setVisibility(View.VISIBLE);
view.getLayoutParams().height = 200;
view.requestLayout();
// this part is required because you did show the row in the onListItemClick
// but it will be lost if you scroll the list and then come back
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mInflater.inflate(R.layout.adapters_showingviews, null);
return v;
}
}
Wenn Sie die Zeile geklickt wechseln wollen (und etwas sagt mir, dass Sie dies wünschen) , zeigen Sie die TextView
auf einen Klick/verstecken Sie die TextView
auf einer anderen Zeile geklickt dann einfach eine else clause
, um die onListItemClick()
Methode hinzufügen und die angeklickt Reihe id
aus dem Status Behälter entfernen und die Zeile wieder her:
//...
else {
status.remove(id);
v.setLayoutParams(new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.MATCH_PARENT));
TextView d = (TextView) v.findViewById(R.id.description);
d.setVisibility(View.GONE);
}
Ihre Antwort auf meine Frage war genau richtig! Ich hatte zuvor einen ähnlichen Ansatz mit ArrayLists versucht, war aber gescheitert. Ich war mit HasMaps nicht vertraut, aber sie sind großartig. Es war ein wenig unklar, wo man die HashMap stecken sollte, also habe ich es wegen der vielen Lesevorgänge in den Adapter als öffentlichen statischen Speicher gesetzt. Mein Projekttermin ist der 4./5. Du bist ein Lebensretter. Meine tiefste Dankbarkeit. – Swiftwork
@Swiftwork Setzen Sie die 'HashMap' dort hin, wo Sie möchten, stellen Sie sicher, dass sie von Ihrer' Aktivität' und auch vom 'Adapter' aus erreichbar ist. Du könntest es mit einer 'ArrayList' machen, aber es ist viel schwieriger zu manipulieren, anstatt einer' get() 'Methode auf einer' HashMap' musst du die gesamte Liste durchlaufen um zu sehen, ob die ID bereits existiert die Position in der Liste etc ... – Luksprog