Android SearchView und DataBinding: Eine Schritt-für-Schritt-Anleitung
In diesem Blogbeitrag zeigen wir Ihnen, wie Sie eine Android-Anwendung mit einer SearchView entwickeln, die es ermöglicht, eine ListView nach bestimmten Begriffen zu durchsuchen. Wir verwenden dabei DataBinding, um Layouts in Activities und Adaptern zu verbinden. DataBinding ist eine nützliche Technik, um den Code übersichtlicher und effizienter zu gestalten.
Was ist die Android SearchView?
Die Android SearchView ist ein Widget, das Suchfunktionen innerhalb Ihrer App bereitstellt. Sie kann sowohl in der ToolBar/ActionBar als auch innerhalb eines Layouts eingesetzt werden. Seit Android 3.0 ist sie verfügbar und bietet viele Funktionen wie z. B. die Textsuche, Vorschläge und sogar Sprachsuche.
Eine einfache Implementierung in einem XML-Layout sieht so aus:
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
In diesem Beispiel verwenden wir das Interface SearchView.OnQueryTextListener sowie die Schnittstelle Filterable, um die Suchanfragen zu bearbeiten. OnQueryTextListener ermöglicht uns, zwei wesentliche Ereignisse abzufangen:
- onQueryTextChange: Wird aufgerufen, wenn der Benutzer Zeichen in das Suchfeld eingibt.
- onQueryTextSubmit: Wird ausgelöst, wenn der Benutzer die Suchanfrage abschickt.
Implementierung eines Beispiels für die Android SearchView
Im folgenden Beispiel erstellen wir eine Activity, die eine SearchView und eine ListView enthält. Die ListView wird mit einer Liste von Monatsnamen gefüllt, die wir durch die Suchanfrage filtern.
activity_main.xml
Das Hauptlayout besteht aus einer SearchView und einer ListView:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true" />
<ListView
android:id="@+id/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/search" />
</RelativeLayout>
</layout>
MainActivity.java
In der MainActivity nutzen wir DataBinding, um die View-Komponenten mit dem Code zu verbinden. Wir erstellen außerdem eine ArrayList mit Monatsnamen und setzen einen Adapter, um diese Liste in der ListView anzuzeigen. Die Suchanfragen werden gefiltert, indem der Adapter die Filter-Methode aufruft, sobald sich der Text in der SearchView ändert.
package com.example.searchviewexample;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import com.example.searchviewexample.databinding.ActivityMainBinding;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
ListAdapter adapter;
List<String> monthList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// Füllen der Monatsnamen
monthList.add("Januar");
monthList.add("Februar");
monthList.add("März");
monthList.add("April");
monthList.add("Mai");
monthList.add("Juni");
monthList.add("Juli");
monthList.add("August");
monthList.add("September");
monthList.add("Oktober");
monthList.add("November");
monthList.add("Dezember");
// Adapter für die Liste setzen
adapter = new ListAdapter(monthList);
binding.listView.setAdapter(adapter);
// SearchView konfigurieren
binding.search.setActivated(true);
binding.search.setQueryHint("Suchbegriff eingeben");
binding.search.onActionViewExpanded();
binding.search.setIconified(false);
binding.search.clearFocus();
// Suchfunktion hinzufügen
binding.search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
});
}
}
ListAdapter.java
Der Adapter dient dazu, die Daten an die ListView zu binden. Hier verwenden wir die Schnittstelle Filterable, um die Liste basierend auf der Suchanfrage zu filtern.
package com.example.searchviewexample;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import com.example.searchviewexample.databinding.RowItemBinding;
import java.util.ArrayList;
import java.util.List;
public class ListAdapter extends BaseAdapter implements Filterable {
List<String> dataList;
List<String> filteredList;
ValueFilter valueFilter;
private LayoutInflater inflater;
public ListAdapter(List<String> list) {
dataList = list;
filteredList = list;
}
@Override
public int getCount() {
return dataList.size();
}
@Override
public String getItem(int position) {
return dataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null) {
inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
RowItemBinding rowBinding = DataBindingUtil.inflate(inflater, R.layout.row_item, parent, false);
rowBinding.stringName.setText(dataList.get(position));
return rowBinding.getRoot();
}
@Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
List<String> filterList = new ArrayList<>();
for (int i = 0; i < filteredList.size(); i++) {
if (filteredList.get(i).toUpperCase().contains(constraint.toString().toUpperCase())) {
filterList.add(filteredList.get(i));
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = filteredList.size();
results.values = filteredList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
dataList = (List<String>) results.values;
notifyDataSetChanged();
}
}
}
Fazit
In diesem Beispiel haben wir eine einfache Android-Anwendung erstellt, die eine Liste von Monatsnamen durchsuchbar macht. Durch die Verwendung von DataBinding und der Schnittstelle Filterable bleibt der Code sauber und übersichtlich.