Motassem Jalal
Motassem Jalal

Reputation: 1314

Android ListFragment: Implementing a search EditText

I'm still new to fragments, I need to add a dynamic search box to filter the list view items while the user is typing in the edit box. I tried the developer documentation https://developer.android.com/training/search/setup.html but it is only about adding a search widget to the action bar and I want to add the search functionality to the edit text box. I'm using ListFragment to handle click events on items.

Here is my code.

ActivityMain.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    mToolbar = (Toolbar) findViewById(R.id.app_bar);
    setSupportActionBar(mToolbar);

    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.main_container, new FragmentNamesList()).commit();

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
<android.support.v7.widget.Toolbar
    android:id="@+id/app_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary"
    android:minHeight="?attr/actionBarSize"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

</android.support.v7.widget.Toolbar>

<LinearLayout
    android:id="@+id/main_container"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</LinearLayout>

</LinearLayout>

FragmentNamesList.java

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.list_container, new FragmentNames()).commit();
        return inflater.inflate(R.layout.frag_names_list, container, false);

frag_names_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_marginBottom="15dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Large Text"
        android:id="@+id/textView"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="25dp" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_search"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:hint="Search" />
</LinearLayout>

<LinearLayout android:id="@+id/list_container"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_marginLeft="15dp"
    android:layout_marginRight="15dp">

</LinearLayout>

</LinearLayout>

I have the list view in a separate layout

frag_list_test.xml

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/list_test">

</ListView>

FragmentNames.java

public static String[] mValues = new String[]{"Item 1", "Item 2", "Item 3"};

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.frag_list_test, container, false);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mValues);
setListAdapter(adapter);
        return rootView;
    }

Upvotes: 1

Views: 2346

Answers (1)

rcbevans
rcbevans

Reputation: 8892

Create your listview as your normally would, but in your ListView adapter, implement the filterable interface:

class CustomAdapter extends BaseAdapter implements Filterable {
    public View getView(){
    ...
    }
    public Integer getCount()
    {
    ...
    }

    @Override
    public Filter getFilter() {

        Filter filter = new Filter() {

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {

                arrayListNames = (List<String>) results.values;
                notifyDataSetChanged();
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {

                FilterResults results = new FilterResults();
                ArrayList<String> FilteredArrayNames = new ArrayList<String>();

                // perform your search here using the searchConstraint String.

                constraint = constraint.toString().toLowerCase();
                for (int i = 0; i < mDatabaseOfNames.size(); i++) {
                    String dataNames = mDatabaseOfNames.get(i);
                    if (dataNames.toLowerCase().startsWith(constraint.toString()))  {
                        FilteredArrayNames.add(dataNames);
                    }
                }

                results.count = FilteredArrayNames.size();
                results.values = FilteredArrayNames;
                Log.e("VALUES", results.values.toString());

                return results;
            }
        };

        return filter;
    }
}

You need to implement the logic for filtering in the performFiltering method. It will pass its result to publishResults.

Given your ListView and the EditText in the layout you can then use something like:

lv = (ListView) findViewById(R.id.list_view);
inputSearch = (EditText) findViewById(R.id.inputSearch);

// Adding items to listview
adapter = new CustomAdapter(...);
lv.setAdapter(adapter);       
inputSearch.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
        // When user changed the Text
        getActivity().this.adapter.getFilter().filter(cs);
    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { }

    @Override
    public void afterTextChanged(Editable arg0) {}
});

This should give you the gist of what you need.

Upvotes: 3

Related Questions