Die Behandlung der Zeilen- / Abschnittslogik ähnlich der von UITableView in iOS ist in Android nicht so einfach wie in iOS. Wenn Sie jedoch RecyclerView verwenden, ist die Flexibilität Ihrer Möglichkeiten weitaus größer.
Am Ende geht es darum, wie Sie herausfinden, welche Art von Ansicht Sie im Adapter anzeigen. Sobald Sie das herausgefunden haben, sollte es einfach sein zu segeln (nicht wirklich, aber zumindest haben Sie das sortiert).
Der Adapter stellt zwei Methoden zur Verfügung, die Sie überschreiben sollten:
getItemViewType(int position)
Die Standardimplementierung dieser Methode gibt immer 0 zurück, was darauf hinweist, dass es nur einen Ansichtstyp gibt. In Ihrem Fall ist dies nicht der Fall, und Sie müssen einen Weg finden, um festzustellen, welche Zeile welchem Ansichtstyp entspricht. Im Gegensatz zu iOS, das dies mit Zeilen und Abschnitten für Sie verwaltet, haben Sie hier nur einen Index, auf den Sie sich verlassen können, und Sie müssen Ihre Entwicklerfähigkeiten einsetzen, um zu wissen, wann eine Position mit einem Abschnittskopf korreliert und wann sie korreliert eine normale Reihe.
createViewHolder(ViewGroup parent, int viewType)
Sie müssen diese Methode trotzdem überschreiben, aber normalerweise ignorieren die Benutzer einfach den Parameter viewType. Je nach Ansichtstyp müssen Sie die richtige Layoutressource aufblasen und Ihren Ansichtshalter entsprechend erstellen. Die RecyclerView behandelt das Recycling verschiedener Ansichtstypen so, dass Konflikte zwischen verschiedenen Ansichtstypen vermieden werden.
Wenn Sie einen Standard-LayoutManager verwenden möchten, z. B. LinearLayoutManager
, sollten Sie bereit sein. Wenn Sie planen, Ihre eigene LayoutManager-Implementierung zu erstellen, müssen Sie etwas härter arbeiten. Die einzige API, mit der Sie wirklich arbeiten müssen, findViewByPosition(int position)
gibt eine bestimmte Ansicht an einer bestimmten Position. Da Sie es wahrscheinlich je nach Typ dieser Ansicht unterschiedlich gestalten möchten , haben Sie einige Möglichkeiten:
Wenn Sie das ViewHolder-Muster verwenden, legen Sie normalerweise das Tag der Ansicht mit dem Ansichtshalter fest. Sie können dies zur Laufzeit im Layout-Manager verwenden, um herauszufinden, um welchen Typ es sich bei der Ansicht handelt, indem Sie im Ansichtshalter ein Feld hinzufügen, das dies ausdrückt.
Da Sie eine Funktion benötigen, die bestimmt, welche Position mit welchem Ansichtstyp korreliert, können Sie diese Methode auch irgendwie global zugänglich machen (möglicherweise eine Singleton-Klasse, die die Daten verwaltet?), Und dann können Sie einfach dieselbe Methode entsprechend abfragen die Position.
Hier ist ein Codebeispiel:
// in this sample, I use an object array to simulate the data of the list.
// I assume that if the object is a String, it means I should display a header with a basic title.
// If not, I assume it's a custom model object I created which I will use to bind my normal rows.
private Object[] myData;
public static final int ITEM_TYPE_NORMAL = 0;
public static final int ITEM_TYPE_HEADER = 1;
public class MyAdapter extends Adapter<ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE_NORMAL) {
View normalView = LayoutInflater.from(getContext()).inflate(R.layout.my_normal_row, null);
return new MyNormalViewHolder(normalView); // view holder for normal items
} else if (viewType == ITEM_TYPE_HEADER) {
View headerRow = LayoutInflater.from(getContext()).inflate(R.layout.my_header_row, null);
return new MyHeaderViewHolder(headerRow); // view holder for header items
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final int itemType = getItemViewType(position);
if (itemType == ITEM_TYPE_NORMAL) {
((MyNormalViewHolder)holder).bindData((MyModel)myData[position]);
} else if (itemType == ITEM_TYPE_HEADER) {
((MyHeaderViewHolder)holder).setHeaderText((String)myData[position]);
}
}
@Override
public int getItemViewType(int position) {
if (myData[position] instanceof String) {
return ITEM_TYPE_HEADER;
} else {
return ITEM_TYPE_NORMAL;
}
}
@Override
public int getItemCount() {
return myData.length;
}
}
Hier ist ein Beispiel, wie diese Ansichtshalter aussehen sollten:
public MyHeaderViewHolder extends ViewHolder {
private TextView headerLabel;
public MyHeaderViewHolder(View view) {
super(view);
headerLabel = (TextView)view.findViewById(R.id.headerLabel);
}
public void setHeaderText(String text) {
headerLabel.setText(text);
}
}
public MyNormalViewHolder extends ViewHolder {
private TextView titleLabel;
private TextView descriptionLabel;
public MyNormalViewHolder(View view) {
super(view);
titleLabel = (TextView)view.findViewById(R.id.titleLabel);
descriptionLabel = (TextView)view.findViewById(R.id.descriptionLabel);
}
public void bindData(MyModel model) {
titleLabel.setText(model.getTitle());
descriptionLabel.setText(model.getDescription());
}
}
In diesem Beispiel wird natürlich davon ausgegangen, dass Sie Ihre Datenquelle (myData) so erstellt haben, dass die Implementierung eines Adapters auf diese Weise einfach ist. Als Beispiel zeige ich Ihnen, wie ich eine Datenquelle erstellen würde, die eine Liste mit Namen und eine Kopfzeile für jedes Mal enthält, wenn sich der erste Buchstabe des Namens ändert (vorausgesetzt, die Liste ist alphabetisch sortiert) - ähnlich wie bei Kontakten Liste würde aussehen wie:
// Assume names & descriptions are non-null and have the same length.
// Assume names are alphabetized
private void processDataSource(String[] names, String[] descriptions) {
String nextFirstLetter = "";
String currentFirstLetter;
List<Object> data = new ArrayList<Object>();
for (int i = 0; i < names.length; i++) {
currentFirstLetter = names[i].substring(0, 1); // get the 1st letter of the name
// if the first letter of this name is different from the last one, add a header row
if (!currentFirstLetter.equals(nextFirstLetter)) {
nextFirstLetter = currentFirstLetter;
data.add(nextFirstLetter);
}
data.add(new MyModel(names[i], descriptions[i]));
}
myData = data.toArray();
}
Dieses Beispiel löst ein ziemlich spezifisches Problem, aber ich hoffe, dies gibt Ihnen einen guten Überblick über den Umgang mit verschiedenen Zeilentypen in einem Recycler und ermöglicht es Ihnen, die erforderlichen Anpassungen in Ihrem eigenen Code vorzunehmen, um Ihren Anforderungen zu entsprechen.