Im diesem Tutorial verwenden wir einen CustomAdapter, der die benutzerdefinierten Zeilen der Android ListView mit einem ArrayList
füllt. Um die Benutzererfahrung zu verbessern, animieren wir die ListView beim Scrollen.
Überblick über den benutzerdefinierten Android ListView Adapter
Der einfachste Adapter zum Befüllen einer Ansicht aus einem ArrayList ist der ArrayAdapter
. Das werden wir in diesem Tutorial umsetzen. Es gibt auch andere Adapter, wie zum Beispiel den CursorAdapter
, der sich direkt an ein Ergebnisset aus einer lokalen SQLite-Datenbank bindet und einen Cursor als Datenquelle verwendet.
Recycling von Zeilen
Wenn eine ListView instanziiert wird und die Zeilen so bevölkert werden, dass die volle Höhe der Liste gefüllt ist, werden keine neuen Zeilenobjekte im Speicher erstellt. Wenn der Benutzer durch die Liste scrollt, werden Elemente, die den Bildschirm verlassen, im Speicher für spätere Verwendung aufbewahrt. Jede neue Zeile, die in den Bildschirm kommt, verwendet dann eine ältere Zeile, die im Speicher aufbewahrt wurde.
Erstellen einer Ansichtsvorlage
Erstellen wir ein XML-Layout, das die Elemente in einer Zeile auf individuelle Weise darstellt. row_item.xml
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="Marshmallow"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/name"
android:layout_marginTop="5dp"
android:text="Android 6.0"
android:textColor="@android:color/black" />
<ImageView
android:id="@+id/item_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@android:drawable/ic_dialog_info" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/version_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="API: "
android:textColor="@android:color/black"
android:textStyle="bold" />
<TextView
android:id="@+id/version_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="23"
android:textAppearance="?android:attr/textAppearanceButton"
android:textColor="@android:color/black"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
In diesem Tutorial werden wir eine Anwendung erstellen, die eine Liste von Zeilen mit Textbeschreibungen und einem Infosymbol enthält. Durch Klicken auf die Zeile wird die Snackbar mit den Textelementen dieser Zeile angezeigt. Durch Klicken auf die Info wird eine Snackbar mit Informationen spezifisch für diese Zeile angezeigt.
Projektstruktur
Code
Wir erstellen eine benutzerdefinierte ListView, indem wir ArrayAdapter mit dem DataModel als Objekt unterklasse. getView() ist die Methode, die die tatsächliche Ansicht zurückgibt, die als Zeile innerhalb der ListView an einer bestimmten Position verwendet wird. Die content_main.xml
enthält die ListView wie unten dargestellt. content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="https://schemas.android.com/apk/res-auto"
tools:context="com.journaldev.customlistview.MainActivity"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main">
<ListView
android:id="@+id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
Das Datenmodell, das in der ArrayList enthalten ist, wird unten angezeigt. DataModel.java
public class DataModel {
String name;
String type;
String version_number;
String feature;
public DataModel(String name, String type, String version_number, String feature ) {
this.name=name;
this.type=type;
this.version_number=version_number;
this.feature=feature;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public String getVersion_number() {
return version_number;
}
public String getFeature() {
return feature;
}
}
Der CustomAdapter, der das DataModel in die ListView einfügt, wird unten gezeigt. CustomAdapter.java
public class CustomAdapter extends ArrayAdapter implements View.OnClickListener{
private ArrayList dataSet;
Context mContext;
// Ansichtscache suchen
private static class ViewHolder {
TextView txtName;
TextView txtType;
TextView txtVersion;
ImageView info;
}
public CustomAdapter(ArrayList data, Context context) {
super(context, R.layout.row_item, data);
this.dataSet = data;
this.mContext=context;
}
@Override
public void onClick(View v) {
int position=(Integer) v.getTag();
Object object= getItem(position);
DataModel dataModel=(DataModel)object;
switch (v.getId())
{
case R.id.item_info:
Snackbar.make(v, "Release date " +dataModel.getFeature(), Snackbar.LENGTH_LONG)
.setAction("No action", null).show();
break;
}
}
private int lastPosition = -1;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Datenobjekt für diese Position abrufen
DataModel dataModel = getItem(position);
// Überprüfen, ob eine vorhandene Ansicht wiederverwendet wird, sonst Ansicht aufblasen
ViewHolder viewHolder; // view lookup cache stored in tag
final View result;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.row_item, parent, false);
viewHolder.txtName = (TextView) convertView.findViewById(R.id.name);
viewHolder.txtType = (TextView) convertView.findViewById(R.id.type);
viewHolder.txtVersion = (TextView) convertView.findViewById(R.id.version_number);
viewHolder.info = (ImageView) convertView.findViewById(R.id.item_info);
result=convertView;
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
result=convertView;
}
Animation animation = AnimationUtils.loadAnimation(mContext, (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top);
result.startAnimation(animation);
lastPosition = position;
viewHolder.txtName.setText(dataModel.getName());
viewHolder.txtType.setText(dataModel.getType());
viewHolder.txtVersion.setText(dataModel.getVersion_number());
viewHolder.info.setOnClickListener(this);
viewHolder.info.setTag(position);
// Die fertige Ansicht zurückgeben, um auf dem Bildschirm gerendert zu werden
return convertView;
}
}
Im obigen Code haben wir einen onClickListener
zum ImageView hinzugefügt, der beim Klicken eine SnackBar mit einer Beschreibung für die jeweilige Zeile anzeigt. Außerdem werden die Listenzeilen beim Scrollen animiert. Die beiden Animations-XML-Ressourcendateien sind unten aufgeführt. down_from_top.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="https://schemas.android.com/apk/res/android"
android:shareInterpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="-100%" android:toYDelta="0%"
android:duration="400" />
</set>
up_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="https://schemas.android.com/apk/res/android"
android:shareInterpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="100%" android:toYDelta="0%"
android:duration="400" />
</set>
Die MainActivity.java
, in der der CustomAdapter der ListView zugewiesen ist, ist unten definiert. Zusammen damit wird ein zufälliges ArrayList von DataModel-Objekten bevölkert. MainActivity.java
public class MainActivity extends AppCompatActivity {
ArrayList dataModels;
ListView listView;
private static CustomAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
listView=(ListView)findViewById(R.id.list);
dataModels= new ArrayList<>();
dataModels.add(new DataModel("Apple Pie", "Android 1.0", "1","September 23, 2008"));
dataModels.add(new DataModel("Banana Bread", "Android 1.1", "2","February 9, 2009"));
dataModels.add(new DataModel("Cupcake", "Android 1.5", "3","April 27, 2009"));
dataModels.add(new DataModel("Donut","Android 1.6","4","September 15, 2009"));
dataModels.add(new DataModel("Eclair", "Android 2.0", "5","October 26, 2009"));
dataModels.add(new DataModel("Froyo", "Android 2.2", "8","May 20, 2010"));
dataModels.add(new DataModel("Gingerbread", "Android 2.3", "9","December 6, 2010"));
dataModels.add(new DataModel("Honeycomb","Android 3.0","11","February 22, 2011"));
dataModels.add(new DataModel("Ice Cream Sandwich", "Android 4.0", "14","October 18, 2011"));
dataModels.add(new DataModel("Jelly Bean", "Android 4.2", "16","July 9, 2012"));
dataModels.add(new DataModel("Kitkat", "Android 4.4", "19","October 31, 2013"));
dataModels.add(new DataModel("Lollipop","Android 5.0","21","November 12, 2014"));
dataModels.add(new DataModel("Marshmallow", "Android 6.0", "23","October 5, 2015"));
adapter= new CustomAdapter(dataModels,getApplicationContext());
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView > parent, View view, int position, long id) {
DataModel dataModel= dataModels.get(position);
Snackbar.make(view, dataModel.getName()+"\n"+dataModel.getType()+" API: "+dataModel.getVersion_number(), Snackbar.LENGTH_LONG)
.setAction("No action", null).show();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Das Menü aufblasen; Dadurch werden Elemente zur Aktionsleiste hinzugefügt, falls vorhanden.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Behandle Klicks auf Elemente der Aktionsleiste hier. Die Aktionsleiste wird
// automatisch Klicks auf die Home-/Up-Schaltfläche behandeln, solange
// du eine übergeordnete Aktivität in der AndroidManifest.xml angibst.
int id = item.getItemId();
//noinspection VereinfachbareAnweisung
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Die Ausgabe der Anwendung in Aktion wird unten angezeigt. Damit endet dieses Tutorial. Sie können das endgültige Android ListView Custom Adapter-Projekt über den folgenden Link herunterladen.
Android ListView Custom Adapter-Projekt herunterladen
Referenz: API-Leitfaden List View