Ich versuche, den besten Weg, um eine einzelne ListView, die verschiedene Layouts für jede Zeile enthält zu bestimmen. Ich weiß, wie man eine benutzerdefinierte Zeile + benutzerdefinierte Array-Adapter erstellen, um eine benutzerdefinierte Zeile für die gesamte Listenansicht zu unterstützen, aber wie kann ich viele verschiedene Zeilenstile in der ListView implementieren?
Antworten
Zu viele Anzeigen?Da Sie wissen, wie viele Arten von Layouts Sie haben werden, können Sie diese Methoden verwenden.
getViewTypeCount()
- Diese Methode gibt Auskunft darüber, wie viele Zeilentypen die Liste enthält.
getItemViewType(int position)
- gibt Informationen darüber zurück, welchen Layout-Typ Sie basierend auf der Position verwenden sollten
Dann blasen Sie das Layout nur auf, wenn es null ist und bestimmen den Typ mit getItemViewType
.
Blick auf diese Anleitung für weitere Informationen.
Um einige Optimierungen in der Struktur zu erreichen, die Sie im Kommentar beschrieben haben, würde ich vorschlagen:
- Speichern von Ansichten in einem Objekt namens
ViewHolder
. Es würde die Geschwindigkeit erhöhen, weil Sie nicht mehr anrufen müssen.findViewById()
jedes Mal ingetView
Methode. Siehe Liste14 in API-Demos . - Erstellen Sie ein allgemeines Layout, das allen Kombinationen von Eigenschaften entspricht und einige Elemente ausblendet, wenn die aktuelle Position sie nicht hat.
Ich hoffe, das wird Ihnen helfen. Wenn Sie einen XML-Stub mit Ihrer Datenstruktur zur Verfügung stellen könnten und Informationen darüber, wie genau Sie sie in Zeilen abbilden wollen, könnte ich Ihnen genauere Ratschläge geben. Nach Pixel.
Ich weiß, wie man eine benutzerdefinierte Zeile + benutzerdefinierte Array-Adapter erstellen, um eine benutzerdefinierte Zeile für die gesamte Listenansicht zu unterstützen. Aber wie kann eine Listenansicht viele verschiedene Zeilenstile unterstützen?
Sie kennen die Grundlagen bereits. Sie müssen nur Ihren benutzerdefinierten Adapter dazu bringen, ein anderes Layout/eine andere Ansicht basierend auf den bereitgestellten Zeilen-/Cursorinformationen zurückzugeben.
A ListView
kann mehrere Zeilenstile unterstützen, da es sich von AdapterView :
Eine AdapterView ist eine Ansicht deren Kinder durch einen Adapter bestimmt werden.
Wenn Sie sich die Adapter werden Sie Methoden sehen, die die Verwendung zeilenspezifischer Ansichten berücksichtigen:
abstract int getViewTypeCount()
// Returns the number of types of Views that will be created ...
abstract int getItemViewType(int position)
// Get the type of View that will be created ...
abstract View getView(int position, View convertView, ViewGroup parent)
// Get a View that displays the data ...
Die beiden letztgenannten Methoden die Position angeben Sie können also damit die Art der Ansicht bestimmen sollten Sie für diese Zeile .
Natürlich verwenden Sie AdapterView und Adapter in der Regel nicht direkt, sondern verwenden eine ihrer Unterklassen oder leiten sie davon ab. Die Unterklassen von Adapter können zusätzliche Funktionen hinzufügen, die die Art und Weise ändern, wie man benutzerdefinierte Layouts für verschiedene Zeilen erhält. Da die für eine bestimmte Zeile verwendete Ansicht durch den Adapter gesteuert wird, besteht der Trick darin, den Adapter dazu zu bringen, die gewünschte Ansicht für eine bestimmte Zeile zurückzugeben. Wie Sie dies tun, hängt vom jeweiligen Adapter ab.
Zum Beispiel, um ArrayAdapter ,
- Überschreiben Sie
getView()
um die gewünschte Ansicht für die angegebene Position aufzublasen, zu füllen und zurückzugeben. DiegetView()
Methode bietet die Möglichkeit der Wiederverwendung von Ansichten über dieconvertView
Parameter.
Aber die Verwendung von Derivaten von CursorAdapter ,
- Überschreiben Sie
newView()
um die gewünschte Ansicht für den aktuellen Cursorstatus (d.h. die aktuelle "Zeile") aufzublasen, aufzufüllen und zurückzugeben [Sie müssen auch diebindView
damit das Widget Ansichten wiederverwenden kann]
Um jedoch die SimpleCursorAdapter ,
- ein definieren
SimpleCursorAdapter.ViewBinder
mit einersetViewValue()
Methode zum Aufblasen, Auffüllen und Zurückgeben der gewünschten Ansicht für eine bestimmte Zeile (aktueller Cursorstatus) und Daten "spalte". Die Methode kann nur die "speziellen" Ansichten definieren und für die "normalen" Bindungen auf das Standardverhalten von SimpleCursorAdapter zurückgreifen.
Schauen Sie in den spezifischen Beispielen/Tutorials für die Art von Adapter nach, die Sie verwenden.
Werfen Sie einen Blick in den unten stehenden Code.
Zunächst erstellen wir benutzerdefinierte Layouts. In diesem Fall sind es vier Typen.
selbst.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#ff500000"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:textColor="@android:color/white"
android:layout_width="match_parent"
android:layout_gravity="center"
android:textSize="24sp"
android:layout_height="wrap_content" />
</LinearLayout>
ungerade.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#ff001f50"
android:gravity="right"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:textColor="@android:color/white"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:textSize="28sp"
android:layout_height="wrap_content" />
</LinearLayout>
weiß.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#ffffffff"
android:gravity="right"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:textColor="@android:color/black"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:textSize="28sp"
android:layout_height="wrap_content" />
</LinearLayout>
schwarz.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#ff000000"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:textColor="@android:color/white"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:textSize="33sp"
android:layout_height="wrap_content" />
</LinearLayout>
Dann erstellen wir das Element der Listenansicht. In unserem Fall mit einem String und einem Typ.
public class ListViewItem {
private String text;
private int type;
public ListViewItem(String text, int type) {
this.text = text;
this.type = type;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
Danach erstellen wir einen Ansichtshalter. Das ist sehr empfehlenswert, da Android OS die Layout-Referenz behält, um Ihr Element wiederzuverwenden, wenn es verschwindet und wieder auf dem Bildschirm erscheint. Wenn Sie diesen Ansatz nicht verwenden, wird Android OS jedes Mal, wenn Ihr Element auf dem Bildschirm erscheint, ein neues Element erstellen, was dazu führt, dass Ihre App Speicherplatz verliert.
public class ViewHolder {
TextView text;
public ViewHolder(TextView text) {
this.text = text;
}
public TextView getText() {
return text;
}
public void setText(TextView text) {
this.text = text;
}
}
Schließlich erstellen wir unseren benutzerdefinierten Adapter, der getViewTypeCount() und getItemViewType(int position) überschreibt.
public class CustomAdapter extends ArrayAdapter {
public static final int TYPE_ODD = 0;
public static final int TYPE_EVEN = 1;
public static final int TYPE_WHITE = 2;
public static final int TYPE_BLACK = 3;
private ListViewItem[] objects;
@Override
public int getViewTypeCount() {
return 4;
}
@Override
public int getItemViewType(int position) {
return objects[position].getType();
}
public CustomAdapter(Context context, int resource, ListViewItem[] objects) {
super(context, resource, objects);
this.objects = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
ListViewItem listViewItem = objects[position];
int listViewItemType = getItemViewType(position);
if (convertView == null) {
if (listViewItemType == TYPE_EVEN) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_even, null);
} else if (listViewItemType == TYPE_ODD) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_odd, null);
} else if (listViewItemType == TYPE_WHITE) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_white, null);
} else {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.type_black, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.text);
viewHolder = new ViewHolder(textView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.getText().setText(listViewItem.getText());
return convertView;
}
}
Und unsere Tätigkeit sieht in etwa so aus:
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // here, you can create a single layout with a listview
listView = (ListView) findViewById(R.id.listview);
final ListViewItem[] items = new ListViewItem[40];
for (int i = 0; i < items.length; i++) {
if (i == 4) {
items[i] = new ListViewItem("White " + i, CustomAdapter.TYPE_WHITE);
} else if (i == 9) {
items[i] = new ListViewItem("Black " + i, CustomAdapter.TYPE_BLACK);
} else if (i % 2 == 0) {
items[i] = new ListViewItem("EVEN " + i, CustomAdapter.TYPE_EVEN);
} else {
items[i] = new ListViewItem("ODD " + i, CustomAdapter.TYPE_ODD);
}
}
CustomAdapter customAdapter = new CustomAdapter(this, R.id.text, items);
listView.setAdapter(customAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView adapterView, View view, int i, long l) {
Toast.makeText(getBaseContext(), items[i].getText(), Toast.LENGTH_SHORT).show();
}
});
}
}
Erstellen Sie nun eine Listenansicht in mainactivity.xml wie folgt
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.shivnandan.gygy.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listView"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="100dp" />
</android.support.design.widget.CoordinatorLayout>
In Ihrem benutzerdefinierten Array-Adapter überschreiben Sie die getView()-Methode, wie Sie es vermutlich kennen. Dann müssen Sie nur noch eine switch-Anweisung oder eine if-Anweisung verwenden, um eine bestimmte benutzerdefinierte Ansicht zurückzugeben, abhängig vom Positionsargument, das an die getView-Methode übergeben wird. Android ist insofern clever, als dass es Ihnen nur eine convertView des passenden Typs für Ihre Position/Zeile liefert; Sie müssen nicht überprüfen, ob sie vom richtigen Typ ist. Sie können Android dabei helfen, indem Sie die Methoden getItemViewType() und getViewTypeCount() entsprechend überschreiben.
Wenn wir verschiedene Arten von Ansichten in der Listenansicht anzeigen müssen, dann ist es gut, getViewTypeCount() und getItemViewType() im Adapter zu verwenden, anstatt eine Ansicht umzuschalten VIEW.GONE und VIEW.VISIBLE kann eine sehr teure Aufgabe innerhalb von getView() sein, die das Scrollen der Liste beeinflussen wird.
Bitte überprüfen Sie dies für die Verwendung von getViewTypeCount() und getItemViewType() im Adapter.
- See previous answers
- Weitere Antworten anzeigen