In this post, you can learn how to implement search suggestions drop down using SearchView with an example. The example shows how to capture search text as user types into search view, display dropdown containing search suggestions from database, and clear search view and do further processing with the selected item from dropdown.
To show SearchView with suggestion dropdown, I’ll take the example which is used to show how to implement search in android apps and display search suggestions and results in list view. You can see the search feature example for classes which are not included in this post.
To handle searches, you need to add OnQueryTextListener to serach view and implement callback method onQueryTextSubmit and onQueryTextChange.
To show search suggestions as dropdown when user types text into SearchView, in the onQueryTextChange call back method mentioned above, cursor adapter needs to be added to SearchView by calling setSuggestionsAdapter method and passing custom cursor adapter which populates data from columns of each row from cursor into views of suggestion dropdown item layout. You can add listener to each item view to handle user selection and do further processing.
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.widget.SearchView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import zoftino.com.androidsearch.R;
public class DealsInfoCursorAdapter extends CursorAdapter {
private LayoutInflater mLayoutInflater;
private Context mContext;
private SearchView searchView;
public DealsInfoCursorAdapter(Context context, Cursor cursor, SearchView sv) {
super(context, cursor, false);
mContext = context;
searchView = sv;
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mLayoutInflater.inflate(R.layout.deal_simple_item_layout, parent, false);
return v;
}
@Override
public void bindView(View view, final Context context, Cursor cursor) {
String deal = cursor.getString(cursor.getColumnIndexOrThrow("deal"));
String cashback = cursor.getString(cursor.getColumnIndexOrThrow("cashback"));
TextView dealsTv = (TextView) view.findViewById(R.id.tv_deal);
dealsTv.setText(deal);
TextView cashbackTv = (TextView) view.findViewById(R.id.tv_cashback);
cashbackTv.setText("Cashback "+cashback);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//take next action based user selected item
TextView dealText = (TextView) view.findViewById(R.id.tv_deal);
searchView.setIconified(true);
Toast.makeText(context, "Selected suggestion "+dealText.getText(),
Toast.LENGTH_LONG).show();
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_deal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv_cashback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_deal"/>
</android.support.constraint.ConstraintLayout>
import android.arch.lifecycle.Observer;
import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.widget.ListView;
import android.widget.Toast;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import zoftino.com.androidsearch.searchview.DealInfo;
import zoftino.com.androidsearch.searchview.DealsInfoCursorAdapter;
import zoftino.com.androidsearch.searchview.DealsListViewAdapter;
import zoftino.com.androidsearch.searchview.LocalRepository;
public class DealsNewSearchActivity extends AppCompatActivity {
private SearchView searchView;
private ListView listView;
private LocalRepository localRepository = new LocalRepository();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.deals_search);
Toolbar myToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(myToolbar);
listView = findViewById(R.id.search_results_list);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_menu, menu);
searchView = (SearchView) menu.findItem(R.id.action_search)
.getActionView();
searchView.setSubmitButtonEnabled(true);
searchView.setOnQueryTextListener(onQueryTextListener);
return super.onCreateOptionsMenu(menu);
}
private SearchView.OnQueryTextListener onQueryTextListener =
new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
query = "%"+query+"%";
localRepository.getDealsListInfo(DealsNewSearchActivity.this, query)
.observe(DealsNewSearchActivity.this,
new Observer<List<DealInfo>>() {
@Override
public void onChanged(@Nullable List<DealInfo> deals) {
if (deals == null) {
return;
}
DealsListViewAdapter adapter =
new DealsListViewAdapter(
DealsNewSearchActivity.this,
R.layout.deal_item_layout, deals);
listView.setAdapter(adapter);
}
});
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
getDealsFromDb(newText);
return true;
}
private void getDealsFromDb(String searchText) {
searchText = "%"+searchText+"%";
Observable.just(searchText).observeOn(Schedulers.computation())
.map( new Function<String, Cursor>(){
@Override
public Cursor apply(String searchStrt) throws Exception {
return localRepository.getDealsCursor(
DealsNewSearchActivity.this, searchStrt);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Cursor>() {
@Override
public void accept(Cursor cursor) throws Exception {
handleResults(cursor);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
handleError(throwable);
}
});
}
};
private void handleResults(Cursor cursor){
searchView.setSuggestionsAdapter(new DealsInfoCursorAdapter
(DealsNewSearchActivity.this, cursor, searchView));
}
private void handleError(Throwable t){
Toast.makeText(this, "Problem in Fetching Deals",
Toast.LENGTH_LONG).show();
}
}
@Dao
public interface DealDAO {
@Query("SELECT * FROM DealInfo WHERE deal LIKE :dealText")
public LiveData<List<DealInfo>> getDealsList(String dealText);
@Query("SELECT * FROM DealInfo WHERE deal LIKE :dealText")
public Cursor getDealsCursor(String dealText);
}
Add below method to LocalRepository class.
public Cursor getDealsCursor(Context context, String query){
return getDealsDAO(context).getDealsCursor(query);
}