可过滤在 Recyclerview 中无法按预期工作

Posted

技术标签:

【中文标题】可过滤在 Recyclerview 中无法按预期工作【英文标题】:Filterable not working as expected in Recyclerview 【发布时间】:2018-11-12 06:31:26 【问题描述】:

所以我尝试在我的应用程序中实现可过滤搜索,假设在输入时开始过滤。但这永远不会发生。而不是显示想要的项目,它只是保留相同的项目并根据找到的项目数量从下到上删除。例如,如果适配器有 4 个项目,

香蕉 苹果 橘子 柠檬

搜索字符串“e” 它会显示: 香蕉 苹果 橙色

因为有 3 个项目包含“e”,它会显示前 3 个。 下面的适配器:

public class MenuListAdapter extends RecyclerView.Adapter<MenuListAdapter.ViewHolder> implements Filterable 
private static final String LOG_TAG = MenuListAdapter.class.getSimpleName();
private LayoutInflater mLayoutInflater;
private int mResourceId;
private ArrayList<Items> items;
private ArrayList<Items> itemsCopy;
private Context context;
private ClickListener clickListener;
private ItemsDAO itemsDAO;
private TextView category_description;

public MenuListAdapter(Context context, ArrayList<Items> items, LayoutInflater inflater, int resourceId, TextView category_description) 
    this.items = new ArrayList<>();
    itemsCopy = new ArrayList<>();
    this.items.addAll(items);
    itemsCopy.addAll(items);
    notifyItemInserted(items.size());
    this.context = context;
    mLayoutInflater = inflater;
    mResourceId = resourceId;
    this.category_description = category_description;


/**
 * Provide a reference to the type of views that you are using (custom ViewHolder)
 */
public class ViewHolder extends RecyclerView.ViewHolder 
    ImageView image;
    TextView title;
    TextView price;

    ViewHolder(View v) 
        super(v);

        title = v.findViewById(R.id.menu_title);
        image = v.findViewById(R.id.image);
        price = v.findViewById(R.id.menu_price);
        itemsDAO = new ItemsDAO(v.getContext());

        //Swipe languages
        if(Languages.getLocale(context).equals("en")) 
            title.setTypeface(AppUtils.getTypeface(context, AppUtils.FONT_REGULAR));
            price.setTypeface(AppUtils.getTypeface(context, AppUtils.FONT_MEDIUM));
            category_description.setTypeface(AppUtils.getTypeface(context, AppUtils.FONT_MEDIUM));
        
        else 
            title.setTypeface(AppUtils.getTypeface(context, AppUtils.AR_FONT_LIGHT));
            price.setTypeface(AppUtils.getTypeface(context, AppUtils.FONT_MEDIUM));
            category_description.setTypeface(AppUtils.getTypeface(context, AppUtils.AR_FONT_MEDIUM));
        

        v.setOnClickListener(new View.OnClickListener()
            @Override
            public void onClick(View v) 
                if (clickListener != null) 
                    clickListener.itemClicked(v, getAdapterPosition(), items.get(getAdapterPosition()).getId(), false);
                    Log.d(LOG_TAG, "Element " + getAdapterPosition() + " clicked.");
                
            
        );

        v.setOnLongClickListener(new View.OnLongClickListener()
            @Override
            public boolean onLongClick(View v) 
                if (clickListener != null) 
                    clickListener.itemClicked(v, getAdapterPosition(), items.get(getAdapterPosition()).getId(), true);

                

                return true;
            
        );

    


// Create new view (invoked by the layout manager)
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) 
    View view = mLayoutInflater.inflate(mResourceId, viewGroup, false);
    return new ViewHolder(view);


// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int position) 
    //    Log.d(LOG_TAG, "Element " + position + " set.");

    final Items menuItems = items.get(position);

    category_description.setText(itemsDAO.getCategoryDescription(menuItems.getCategory_code()+ 9000));
    // Get element from MenuItems object at this position and replace the contents of the view
    // with that element
    //IMAGE STATIC HERE
    Bitmap decodedByte = BitmapFactory.decodeByteArray(Base64.decode(menuItems.getImage(), Base64.DEFAULT), 0, Base64.decode(menuItems.getImage(), Base64.DEFAULT).length);
    viewHolder.image.setImageBitmap(decodedByte);
    viewHolder.image.setTag(menuItems.getId());
    //Swipe languages
    if(Languages.getLocale(context).equals("en")) 
        viewHolder.title.setText(menuItems.getName());
    
    else 
        viewHolder.title.setText(menuItems.getName2());
    

    viewHolder.price.setText(Localization.getLocalize(context) + " " + Double.parseDouble(String.valueOf(menuItems.getPrice())));


@Override
public int getItemCount() 
    return items.size();


public void setClickListener(ClickListener clickListener)
    this.clickListener = clickListener;




// An interface to Define click listener for the ViewHolder's View from any where.
public interface ClickListener
    void itemClicked(View view, int position, int id, boolean isLongClick);


@Override
public Filter getFilter() 
    return new Filter() 
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) 
            items.clear();
            String charString = charSequence.toString();
            if (charString.isEmpty()) 
                items.addAll(itemsCopy);
             else 
                charString = charString.toLowerCase();
                int counter = 0;
                for(Items item: itemsCopy)
                    if(item.getName().toLowerCase().contains(charString))
                        items.add(item);
                    
                    else
                    
                        notifyItemRemoved(counter);
                    
                    counter++;
                
            

            FilterResults filterResults = new FilterResults();
            filterResults.values = items;
            return filterResults;
        

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) 
            items = (ArrayList<Items>) filterResults.values;

            // refresh the list with filtered data
            notifyDataSetChanged();
        
    ;

片段中的searchView代码

case R.id.action_search: 
            android.support.v7.widget.SearchView searchView = (android.support.v7.widget.SearchView) item.getActionView();
            searchView.setOnQueryTextListener(
                    new android.support.v7.widget.SearchView.OnQueryTextListener() 
                        @Override
                        public boolean onQueryTextSubmit(String query) 
                            menuListAdapter.getFilter().filter(query);
                            return false;
                        

                        @Override
                        public boolean onQueryTextChange(String query) 
                            menuListAdapter.getFilter().filter(query);
                            return false;
                        
                    
            );

            return true;
        

这是正在发生的事情,键入时没有任何变化:

提交搜索后,会发生什么情况,有 3 个项目包含“ca”,所以它只显示前 3 个项目:

当我点击第一个项目时,它会传递正确的 id 并导航到包含“ca”的正确过滤项目。

这是给pskink的

public class MenuListAdapter extends MatchableRVArrayAdapter<Items, MenuListAdapter.ViewHolder> 
private static final String LOG_TAG = MenuListAdapter.class.getSimpleName();
private ClickListener clickListener;
private ItemsDAO itemsDAO;
private TextView category_description;

public MenuListAdapter(Context context, int resource, List<Items> objects, TextView category_description) 
    super(context, resource, objects);
    this.category_description = category_description;



/**
 * Provide a reference to the type of views that you are using (custom ViewHolder)
 */
public class ViewHolder extends RecyclerView.ViewHolder 
    ImageView image;
    TextView title;
    TextView price;

    ViewHolder(View v) 
        super(v);

        title = v.findViewById(R.id.menu_title);
        image = v.findViewById(R.id.image);
        price = v.findViewById(R.id.menu_price);
        itemsDAO = new ItemsDAO(v.getContext());

        //Swipe languages
        if(Languages.getLocale(getContext()).equals("en")) 
            title.setTypeface(AppUtils.getTypeface(getContext(), AppUtils.FONT_REGULAR));
            price.setTypeface(AppUtils.getTypeface(getContext(), AppUtils.FONT_MEDIUM));
            category_description.setTypeface(AppUtils.getTypeface(getContext(), AppUtils.FONT_MEDIUM));
        
        else 
            title.setTypeface(AppUtils.getTypeface(getContext(), AppUtils.AR_FONT_LIGHT));
            price.setTypeface(AppUtils.getTypeface(getContext(), AppUtils.AR_FONT_MEDIUM));
            category_description.setTypeface(AppUtils.getTypeface(getContext(), AppUtils.AR_FONT_MEDIUM));
        

        v.setOnClickListener(new View.OnClickListener()
            @Override
            public void onClick(View v) 
                if (clickListener != null) 
                    clickListener.itemClicked(v, getAdapterPosition(), getAdapterPosition(), false);
                    Log.d(LOG_TAG, "Element " + getAdapterPosition() + " clicked.");
                
            
        );

        v.setOnLongClickListener(new View.OnLongClickListener()
            @Override
            public boolean onLongClick(View v) 
                if (clickListener != null) 
                    clickListener.itemClicked(v, getAdapterPosition(), getAdapterPosition(), true);

                

                return true;
            
        );

    



@Override
protected ViewHolder onCreateHolder(View view) 
    return new ViewHolder(view);


@Override
protected void onBindHolder(Items item, ViewHolder holder, int position) 
    category_description.setText(itemsDAO.getCategoryDescription(item.getCategory_code()+ 9000));
    // Get element from MenuItems object at this position and replace the contents of the view
    // with that element
    //IMAGE STATIC HERE
    Bitmap decodedByte = BitmapFactory.decodeByteArray(Base64.decode(item.getImage(), Base64.DEFAULT), 0, Base64.decode(item.getImage(), Base64.DEFAULT).length);
    holder.image.setImageBitmap(decodedByte);
    holder.image.setTag(item.getId());
    //Swipe languages
    if(Languages.getLocale(getContext()).equals("en")) 
        holder.title.setText(item.getName());
    
    else 
        holder.title.setText(item.getName2());
    

    holder.price.setText(Localization.getLocalize(getContext()) + " " + Double.parseDouble(String.valueOf(item.getPrice())));



public void setClickListener(ClickListener clickListener)
    this.clickListener = clickListener;




// An interface to Define click listener for the ViewHolder's View from any where.
public interface ClickListener
    void itemClicked(View view, int position, int id, boolean isLongClick);


@Override
protected boolean matches(Items value, CharSequence constraint, CharSequence lowerCaseConstraint) 
    return super.matches(value, constraint, lowerCaseConstraint);

当我开始输入时,仍然没有任何变化:

提交搜索后,会发生什么情况,有 3 个项目包含“ca”,所以它只显示前 3 个项目:

当我点击第一个项目时,它会传递正确的 id 并导航到包含“ca”的正确过滤项目。

【问题讨论】:

扩展this通用Filterable适配器并覆盖matches()方法 类似class A extends MatchableRVArrayAdapter&lt;Items, A.VH&gt; ... 当然你不需要这样的东西:private LayoutInflater mLayoutInflater; private int mResourceId; private ArrayList&lt;Items&gt; items; private ArrayList&lt;Items&gt; itemsCopy; private Context context; - 只需删除它 我将你的类扩展到我的适配器类,它仍然显示相同的项目,但根据找到的项目大小减小列表的大小。 那你修改的代码是什么?你说的" and it still shows the same items"是什么意思? 【参考方案1】:

我发现实现 AlphaInAnimationAdapter 会导致问题,我只需要删除

alphaAdapter = new AlphaInAnimationAdapter(menuListAdapter);
            mRecyclerView.setAdapter(new ScaleInAnimationAdapter(alphaAdapter));

从我的代码中,它现在可以完美地与 Pskink 适配器类一起工作。感谢 Pskink 的帮助!

【讨论】:

以上是关于可过滤在 Recyclerview 中无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

增强共享库中的日志记录通道过滤在 linux 上无法按预期工作

RecyclerView 没有按预期滚动

Primefaces Accordion + Datatable过滤器/多项选择无法按预期工作

如何显示按最喜欢的评论过滤的recyclerview项目?

使用 laravel 和 jquery 分页无法按预期工作

在雪花中按分区过滤