简体   繁体   中英

Adding filtering/search to my RecyclerView

I have a RecyclverView set up which works perfectly (it may not be the 'best practice' but it works)

The RecyclerView method I implemented was from this video

For this I did the below:

  • I have added a RecyclerView in my activity_main.xml layout with an id @+id/recycler_view
  • Create a RecyclerView Adapter class called RecyclerViewAdapter
  • Create a listitem layout called layout_listitem.xml

This worked perfectly and pulls the information from a values xml called sheep.xml

When you click on one of the items it loads activity GalleryActivity which presents the information from that item position in a new activity_gallery.xml layout.

image examples below:

在此处输入图像描述

I want to add filtering/search to my RecyclerView. I have followed many guides online from various people and yet still can't get it to work. I created a menu layouts, set up a filterable method and a 'new list' to store the filtered results

Followed this this and this

Can someone please help me point me in the right direction of a guide I can use with my current set up. I am fairly primitive in my coding knowledge so please be kind.

MainActivity

package com.british.sheep.breeds;

import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity{
    String[ ] url;
    String[ ] name;
    String[ ] type;
    String[ ] established;
    String[ ] handle;
    String[ ] colour;
    String[ ] fleece;
    String[ ] staple;
    String[ ] micron;
    String[ ] gallery;


    private static final String TAG = "MainActivity";
    //vars
    private ArrayList<String> mNames = new ArrayList<>();
    private ArrayList<String> mImageUrls = new ArrayList<>();
    private ArrayList<String> mTypes = new ArrayList<>();
    private ArrayList<String> mEstablisheds = new ArrayList<>();
    private ArrayList<String> mHandles = new ArrayList<>();
    private ArrayList<String> mColours = new ArrayList<>();
    private ArrayList<String> mFleeces = new ArrayList<>();
    private ArrayList<String> mStaples = new ArrayList<>();
    private ArrayList<String> mMicrons = new ArrayList<>();
    private ArrayList<String> mGalleryUrls = new ArrayList<>();



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Resources res = getResources();

        url = res.getStringArray( R.array.url ) ;
        name = res.getStringArray( R.array.name ) ;
        type = res.getStringArray( R.array.type ) ;
        established = res.getStringArray( R.array.established ) ;
        handle = res.getStringArray( R.array.handle ) ;
        colour = res.getStringArray( R.array.colour ) ;
        fleece = res.getStringArray( R.array.fleece ) ;
        staple = res.getStringArray( R.array.staple ) ;
        micron = res.getStringArray( R.array.micron ) ;
        gallery = res.getStringArray( R.array.gallery ) ;

        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
        Log.d(TAG, "onCreate: started.");
        initImageBitmaps();
    }
    private void initImageBitmaps(){
        Log.d(TAG, "initImageBitmaps: preparing bitmaps.");
        for (int i = 0; i < url.length; i++) {
            mImageUrls.add(url[i]);
            mNames.add(name[i]);
            mTypes.add(type[i]);
            mEstablisheds.add(established[i]);
            mHandles.add(handle[i]);
            mColours.add(colour[i]);
            mFleeces.add(fleece[i]);
            mStaples.add(staple[i]);
            mMicrons.add(micron[i]);
            mGalleryUrls.add(gallery[i]);
        }
        initRecyclerView();
    }



    private void initRecyclerView(){
        Log.d(TAG, "initRecyclerView: init recyclerview.");
        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, mNames, mImageUrls, mTypes, mEstablisheds, mHandles, mColours, mFleeces, mStaples, mMicrons, mGalleryUrls);
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }

}

RecyclerViewAdapter

package com.british.sheep.breeds;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    private ArrayList<String> mImageNames = new ArrayList<>();
    private ArrayList<String> mImages = new ArrayList<>();
    private ArrayList<String> mImageTypes = new ArrayList<>();
    private ArrayList<String> mImageEstablisheds = new ArrayList<>();
    private ArrayList<String> mImageHandles = new ArrayList<>();
    private ArrayList<String> mImageColours = new ArrayList<>();
    private ArrayList<String> mImageFleeces = new ArrayList<>();
    private ArrayList<String> mImageStaples = new ArrayList<>();
    private ArrayList<String> mImageMicrons = new ArrayList<>();
    private ArrayList<String> mImageGallerys = new ArrayList<>();
    private Context mContext;

    public RecyclerViewAdapter(Context context, ArrayList<String> imageNames, ArrayList<String> images, ArrayList<String> types, ArrayList<String> establisheds, ArrayList<String> handles, ArrayList<String> colours, ArrayList<String> fleeces, ArrayList<String> staples, ArrayList<String> microns ,ArrayList<String> gallerys ) {
        mImageNames = imageNames;
        mImages = images;
        mImageTypes = types;
        mImageEstablisheds = establisheds;
        mImageHandles = handles;
        mImageColours = colours;
        mImageFleeces = fleeces;
        mImageStaples = staples;
        mImageMicrons = microns;
        mImageGallerys = gallerys;
        mContext = context;

    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {


        Glide.with(mContext)
                .asBitmap()
                .load(mImages.get(position))
                .into(holder.image);

        holder.imageName.setText(mImageNames.get(position));


        holder.parentLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {


                Intent intent = new Intent(mContext, GalleryActivity.class);
                intent.putExtra("image_url", mImages.get(position));
                intent.putExtra("image_name", mImageNames.get(position));
                intent.putExtra("image_type", mImageTypes.get(position));
                intent.putExtra("image_established", mImageEstablisheds.get(position));
                intent.putExtra("image_handle", mImageHandles.get(position));
                intent.putExtra("image_colour", mImageColours.get(position));
                intent.putExtra("image_fleece", mImageFleeces.get(position));
                intent.putExtra("image_staple", mImageStaples.get(position));
                intent.putExtra("image_micron", mImageMicrons.get(position));
                intent.putExtra("image_gallery", mImageGallerys.get(position));

                mContext.startActivity(intent);
            }
        });
    }

    @Override
    public int getItemCount() {
        return mImageNames.size();
    }

        public class ViewHolder extends RecyclerView.ViewHolder{

        ImageView image;
        TextView imageName;
        TextView imageType;
        TextView imageEstablished;
        TextView imageHandle;
        TextView imageColour;
        TextView imageFleece;
        TextView imageStaple;
        TextView imageMicron;
        ImageView imageGallery;
        RelativeLayout parentLayout;


        public ViewHolder(View itemView) {
            super(itemView);
            image = itemView.findViewById(R.id.image);
            imageName = itemView.findViewById(R.id.image_name);
            parentLayout = itemView.findViewById(R.id.parent_layout);
            imageType = itemView.findViewById(R.id.image_type);
            imageEstablished = itemView.findViewById(R.id.image_established);
            imageHandle = itemView.findViewById(R.id.image_handle);
            imageColour = itemView.findViewById(R.id.image_colour);
            imageFleece = itemView.findViewById(R.id.image_fleece);
            imageStaple = itemView.findViewById(R.id.image_staple);
            imageMicron = itemView.findViewById(R.id.image_micron);
            imageGallery = itemView.findViewById(R.id.image_gallery);

        }


        }



}

GalleryActivity

package com.british.sheep.breeds;

import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.bumptech.glide.Glide;

public class GalleryActivity extends AppCompatActivity {

    private static final String TAG = "GalleryActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gallery);
        overridePendingTransition(R.anim.mtrl_bottom_sheet_slide_in, R.anim.mtrl_bottom_sheet_slide_out);
        Log.d(TAG, "onCreate: started.");

        getIncomingIntent();
    }

    @Override
    public void onBackPressed() {
        finishMyActivity();
    }

    public void finishMyActivity() {
        finish();
        overridePendingTransition(R.anim.mtrl_bottom_sheet_slide_in, R.anim.mtrl_bottom_sheet_slide_out);
    }


    private void getIncomingIntent() {
        Log.d(TAG, "getIncomingIntent: checking for incoming intents.");

        if (getIntent().hasExtra("image_url") && getIntent().hasExtra("image_name") && getIntent().hasExtra("image_type") && getIntent().hasExtra("image_established") && getIntent().hasExtra("image_handle") && getIntent().hasExtra("image_colour") && getIntent().hasExtra("image_fleece") && getIntent().hasExtra("image_staple") && getIntent().hasExtra("image_micron") && getIntent().hasExtra("image_gallery")) {
            Log.d(TAG, "getIncomingIntent: found intent extras.");

            String imageUrl = getIntent().getStringExtra("image_url");
            String imageName = getIntent().getStringExtra("image_name");
            String imageType = getIntent().getStringExtra("image_type");
            String imageEstablished = getIntent().getStringExtra("image_established");
            String imageHandle = getIntent().getStringExtra("image_handle");
            String imageColour = getIntent().getStringExtra("image_colour");
            String imageFleece = getIntent().getStringExtra("image_fleece");
            String imageStaple = getIntent().getStringExtra("image_staple");
            String imageMicron = getIntent().getStringExtra("image_micron");
            String imageGallery = getIntent().getStringExtra("image_gallery");
            setImage(imageUrl, imageName, imageType, imageEstablished, imageHandle, imageColour, imageFleece, imageStaple, imageMicron, imageGallery);
        }
    }

    private void setImage(String imageUrl, String imageName, String imageType, String imageEstablished, String imageHandle, String imageColour, String imageFleece, String imageStaple, String imageMicron, String imageGallery) {
        Log.d(TAG, "setImage: setting te image and name to widgets.");

        //TextView name = findViewById(R.id.image_description);
        //name.setText(imageName);
        setTitle(imageName);

        TextView type = findViewById(R.id.image_type);
        type.setText(imageType);

        TextView established = findViewById(R.id.image_established);
        established.setText(imageEstablished);

        TextView handle = findViewById(R.id.image_handle);
        handle.setText(imageHandle);

        TextView colour = findViewById(R.id.image_colour);
        colour.setText(imageColour);

        TextView fleece = findViewById(R.id.image_fleece);
        fleece.setText(imageFleece);

        TextView staple = findViewById(R.id.image_staple);
        staple.setText(imageStaple);

        TextView micron = findViewById(R.id.image_micron);
        micron.setText(imageMicron);

        ImageView gallery = findViewById(R.id.image_gallery);
        Glide.with(this)
                .asBitmap()
                .load(imageGallery)
                .into(gallery);
    }


}

Here is an example, how you can implement a search filter on your RecyclerView. I am going to take mImageNames arrayList on which I'll perform the filter. There are a couple of things we need to do.

(Make a copy of list, Implement Filterable to your adapter class, write filter logic and return the filtered value to your MainActivity class)

public class RecyclerViewAdapter extends 
RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements Filterable {
private ArrayList<String> mImageNames = new ArrayList<>();
private ArrayList<String> copyImageNames ;

public RecyclerViewAdapter (ArrayList<String> imageNames) {
mImageNames = imageNames;
copyImageNames = new ArrayList<>(imageNames);
} } 

After your implement Filterable you need to override this method inside your adapter class.

@Override
public Filter getFilter() { return filter; }

After that we will write the logic to perform filter.I am considering that your mImageNames list has name of all the sheeps (Balwen,Beltex.....) so that you can filter by their names.

    Filter filter = new Filter() {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        ArrayList<String> filteredList = new ArrayList<>();
        if (constraint == null || constraint.length() == 0) {
            filteredList.addAll(copyImageNames );
        } else {
            String filterPattern = constraint.toString().toLowerCase().trim();
            for (String s : copyImageNames ) {
                if (s.contains(filterPattern)) {
                    filteredList.add(s);
                }
            }
        }
        FilterResults results = new FilterResults();
        results.values = filteredList;
        return results;
    }
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        mImageNames .clear();
        mImageNames .addAll((List) results.values);
        notifyDataSetChanged();
    }
};

Adapter is done, now back to MainActivity Create a menu directory under res folder and save this xml code.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
    android:id="@+id/action_search"
    android:icon="@drawable/ic_search"
    android:title="Search"
    app:actionViewClass="androidx.appcompat.widget.SearchView"
    app:showAsAction="always|collapseActionView" /></menu>

Now we will inflate the menu and appply the filter to your adapter.

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.my_menu, menu);
    MenuItem item =menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) item.getActionView();
    searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            adapter.getFilter().filter(newText);
            return false;
        }
    });
    return true;
}

First of all create in resources menu for your toolbar:

<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item android:id="@+id/menu_item_search"
        android:title="@string/search"
        app:actionViewClass="androidx.appcompat.widget.SearchView"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/menu_setSort"
        android:icon="@drawable/ic_sort_off_24dp"
        android:title="@string/routes_sort"
        app:showAsAction="ifRoom" />

</menu>

add this line to one of items: app:actionViewClass="androidx.appcompat.widget.SearchView" then in your activity with RecyclerView:

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.your_menu, menu);
        MenuItem sortIcon = menu.findItem(R.id.menu_setSort);
        MenuItem searchItem = menu.findItem(R.id.menu_item_search);
        SearchView searchView = (SearchView) searchItem.getActionView();

        searchView.setOnQueryTextListener(this);
        return true;
    }

Do not forget to implement this interface to your Activivty - implements SearchView.OnQueryTextListener

Because of this interface you implemetnt this methods:

  @Override
    public boolean onQueryTextSubmit(String query) {
        searchResult(query);
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        return false;
}

You better make a class instead of all this ArrayLists:

public class OneSheep {
    private String mFleeces ;
    private String mStaples ;
    private String mMicrons ;
    private String mGalleryUrls;
    private String mNames;
    private String mImageUrls ;
    private String mTypes;
    private String mEstablishedsist;
    private String mHandles ;
    private String mColours ;

    public OneSheep(String names, String imageUrls, String types, String establishedsist, String handles, String colours, String fleeces, String staples, String microns, String galleryUrls) {
        mNames = names;
        mImageUrls = imageUrls;
        mTypes = types;
        mEstablishedsist = establishedsist;
        mHandles = handles;
        mColours = colours;
        mFleeces = fleeces;
        mStaples = staples;
        mMicrons = microns;
        mGalleryUrls = galleryUrls;
    }

    public String getNames() {
        return mNames;
    }

    public String getImageUrls() {
        return mImageUrls;
    }

    public String getTypes() {
        return mTypes;
    }

    public String getEstablishedsist() {
        return mEstablishedsist;
    }

    public String getHandles() {
        return mHandles;
    }

    public String getColours() {
        return mColours;
    }

    public String getFleeces() {
        return mFleeces;
    }


    public String getStaples() {
        return mStaples;
    }

    public String getMicrons() {
        return mMicrons;
    }

    public String getGalleryUrls() {
        return mGalleryUrls;
    }
}

In your Activity make only one ArrayList<OneSheep> mSheeps , pass it to your RecaclerView Adapter and this way it is gonna be mach easier to maintain that code. Make your RecyclerView global for MainActivity, call it for example recyclerView and your searchResult() method will look somethink like that:

private void searchResult(String query) {
        ArrayList<OneSheep> newSheepsList = new ArrayList<>();
        for (OneSheep sheep:mSheeps) {
            if (sheep.getNames().contains(query)){
                newSheepsList.add(sheep);
                break;
            }
            if (sheep.getTypes().contains(query)){
                newSheepsList.add(sheep);
                break;
            }
            //add any conditions here
        }
        RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, newSheepsList);
        recyclerView.setAdapter(adapter);
    }

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM