Sivabalan D
Sivabalan D

Reputation: 113

SearchView in activity toolbar and filter to fragment

I have given SearchView in activity with custom toolbar and filter data goes to fragment. When I click on the search icon,toolbar size increasing. Navigation bar is used in that activity,may be it is issue?. It is working with separate activity without navigation bar.vb

Here is my code: Activity.xml :

<android.support.design.widget.AppBarLayout
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="wrap_content"
app:elevation="5dp">

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    style="@style/Toolbar"
    app:contentInsetEnd="5dp"
    app:contentInsetLeft="15dp"
    app:contentInsetRight="5dp"
    app:contentInsetStart="15dp"
    app:theme="@style/AppTheme.Toolbar"
    app:popupTheme="@style/AppTheme.PopupOverlay"
    app:contentInsetStartWithNavigation="15dp"
    app:titleTextColor="@color/colorWhite"
    tools:targetApi="lollipop">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/toolbar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_centerInParent="true"
            android:layout_gravity="start"
            android:gravity="center"
            android:text=""
            android:textAllCaps="false"
            android:textColor="@color/colorWhite"
            android:textSize="16sp"
            android:textStyle="bold"
            tools:ignore="RelativeOverlap" />


        <TextView
            android:id="@+id/toolbar_student_details"
            android:layout_width="120dp"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_gravity="end"
            android:gravity="center"
            android:text=""
            android:textAllCaps="false"
            android:textColor="@color/colorWhite"
            android:textSize="16sp"
            tools:ignore="RelativeOverlap" />

        <Spinner
            android:id="@+id/toolbar_student_details_spinner"
            android:spinnerMode="dropdown"
            android:layout_width="120dp"
            android:backgroundTint="@color/colorWhite"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_gravity="end"
            android:textAllCaps="false"
            android:textColor="@color/colorWhite"
            android:textSize="16sp"
            tools:ignore="RelativeOverlap"
            android:visibility="gone"
            >
        </Spinner>

        <ImageView
            android:id="@+id/admin_image"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_marginEnd="10dp"
            android:layout_marginRight="10dp"
            android:contentDescription="@string/app_name"
            android:visibility="gone" />
    </RelativeLayout>


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

    </android.support.design.widget.AppBarLayout>

Fragament code:

   @Override
   public View onCreateView(@NonNull LayoutInflater inflater, 
 ViewGroup 
container, Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView= 
       inflater.inflate(R.layout.fragment_staff_fragment_admin, 
            container, false);
    setHasOptionsMenu(true);
    ButterKnife.bind(this, rootView);
    return rootView;
}

    @Override
   public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    getBaseActivity().getMenuInflater().inflate(R.menu.menu_main, 
     menu);
    SearchView searchView;
    // Associate searchable configuration with the SearchView
    SearchManager searchManager = (SearchManager)getBaseActivity(). 
   getSystemService(Context.SEARCH_SERVICE);
    searchView = (SearchView) menu.findItem(R.id.action_search)
            .getActionView();
    assert searchManager != null;
    searchView.setSearchableInfo(searchManager
            .getSearchableInfo(getBaseActivity().getComponentName()));
    searchView.setMaxWidth(Integer.MAX_VALUE);

    // listening to search query text change
    searchView.setOnQueryTextListener(new 
     SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            // filter recycler view when query submitted
            mAdapter.getFilter().filter(query);
            return false;
        }

        @Override
        public boolean onQueryTextChange(String query) {
            // filter recycler view when text is changed
            mAdapter.getFilter().filter(query);
            return false;
        }
    });
 }

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_search) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

enter image description here

Upvotes: 3

Views: 5108

Answers (2)

Patrick
Patrick

Reputation: 204

In my app, I've several fragments inside a ViewPager + TabLayout. I don't understand how you can basically filter the RecyclerView realtime. To me it seems that your concept is just filtering once, i.e. as long as you don't call the method again, the list will not be filtered. Do you have some further insights?

Upvotes: 0

Panos Gr
Panos Gr

Reputation: 677

You should listen to changes in the Activity and send the result to your Fragment as your SearchView is inside the Activity ( in the custom Toolbar). One of the problems you may be facing is that the searchview is null when you are calling it.

I recommend doing this through your ViewModel if you are using Android Architecture Components and the MVVM pattern as follows:

  1. Listen to changes in your Activity
// listening to search query text change
    searchView.setOnQueryTextListener(new 
     SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            //filter the data in step 2
            return false;
        }

        @Override
        public boolean onQueryTextChange(String query) {
            // filter data in step 2
            return false;
        }
    });
  1. Send the query to your ViewModel function to filter the data

inside your Activity:

        ...
        @Override
        public boolean onQueryTextSubmit(String query) {
            //filter the data
            viewModel.filterData(query);
            return false;
        }
        ...

inside your ViewModel:

       public List<String> listOfData = getListOfData();
       public LiveData<List<String>> searchResults = new MutableLiveData(listOfData);

       // filter list of data when query submitted
       public void filterData(String query) {
            //filter outside of your RecyclerView Adapter through your listOfData variable
            searchResults.value = getFilter().filter(query);
       }

       public LiveData<List<String>> getSearchResults() {
            return searchResults;
       }

by setting the result on your LiveData through searchResults.value you can listen to it change directly from your Fragment, thus completing the communication between your Activity and your Fragment RecyclerView through this variable in step 3.

  1. Observe the ViewModel variable inside your Fragment & update the Adapter

inside your Fragment

        override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)


            viewModel.getSearchResults().observe(this, { searchResults->
                Log.w("onActivityCreated()", "new search list received :" +searchResults)
                mAdapter.updateList(searchResults)
                listItemsAdapter.notifyDataSetChanged()
            });

    }

With these changes, you're filtering from the Activity SearchView and sending the results to the Fragment RecyclerView which should work. If you are using another pattern, the important thing is to send the query from your Activity to your Fragment instead of listening in your Fragment only.

If you aren't using these yet, I recommend taking a look at AAC with MVVM. You can find more info in the Android Developers Documentation about these concepts.

Hope this helped, good luck.

Upvotes: 0

Related Questions