How to highlight filtered text in RecyclerView when using SearchView widget

只谈情不闲聊 提交于 2019-12-05 02:19:14

问题


How to highlight search text result in RecyclerView. I found some posts regarding Spannable TextView, but not sure where to implement in my case. Appreciate you can look and assist.

MainActivity or Chapter1

 public class Chapter1 extends AppCompatActivity implements SearchView.OnQueryTextListener {
        MyRecAdapter myRecAdapter;
        RecyclerView recyclerView;
        List<Post> list;        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(layout.chapter1_main);
            recyclerView = (RecyclerView) findViewById(R.id.myrec);
            createdata();
            myRecAdapter = new MyRecAdapter(list, Chapter1.this);
            recyclerView.setLayoutManager(new LinearLayoutManager(Chapter1.this));
            recyclerView.setAdapter(myRecAdapter);
        }        
        void createdata() {             
            list = new ArrayList<>();               
            String topic_1_1 = getResources().getString(string.topic_1_1);
            String text_1_1 = getString(string.text_1_1);
            String topic_1_2 = getResources().getString(string.topic_1_2);
            String topic_1_3 = getResources().getString(string.topic_1_3);
            String text_1_3 = getString(string.text_1_3);         
            list.add(new Post(topic_1_1, text_1_1));
            list.add(new Post(topic_1_2, ""));
            list.add(new Post(topic_1_3, text_1_3));               

        }       

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.menu_search, menu);
            getMenuInflater().inflate(R.menu.main, menu);        
            MenuItem item = menu.findItem(R.id.menu_search);
            SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);        
            searchView.setOnQueryTextListener(this);        
            return super.onCreateOptionsMenu(menu);
        }     


        @Override
        public boolean onQueryTextChange(String newText) {        

            final List<Post> filteredModelList = filter(list, newText);        
            if (filteredModelList.size() > 0) {        
                myRecAdapter.setFilter(filteredModelList);
                return true;
            } else {
                Toast.makeText(Chapter1.this, "Not Found", Toast.LENGTH_SHORT).show();
                return false;
            }
        }        
        private List<Post> filter(List<Post> models, String query ) {
            query = query.toLowerCase();        
            final List<Post> filteredModelList = new ArrayList<>();
            for (Post model : models) {        
                final String text = model.getPostTitle().toLowerCase();
                final String text_sub = model.getPostSubTitle().toLowerCase();        
                if (text.contains(query)) {
                    filteredModelList.add(model);

                }
                else {
                    if (text_sub.contains(query)) {
                        filteredModelList.add(model);
                    }        
                }     
            }
            createdata();
            myRecAdapter = new MyRecAdapter(filteredModelList, Chapter1.this);
            recyclerView.setLayoutManager(new LinearLayoutManager(Chapter1.this));
            recyclerView.setAdapter(myRecAdapter);
            myRecAdapter.notifyDataSetChanged();
            return filteredModelList;
        }
    }

Adapter

public class MyRecAdapter extends RecyclerView.Adapter<MyRecAdapter.VH> {
        public List<Post> parkingList;        
        public Context context;
        ArrayList<Post> mCountryModel;        
        public MyRecAdapter(List<Post> parkingList, Context context) {
            this.parkingList = parkingList;
            this.context = context;
        }        
        @Override
        public MyRecAdapter.VH onCreateViewHolder(ViewGroup parent, int viewType) {
            return new MyRecAdapter.VH(LayoutInflater.from(parent.getContext()).inflate(R.layout.mycardview, parent, false));
        }        
        @Override
        public void onBindViewHolder(MyRecAdapter.VH holder, int position) {       
                holder.t1.setText(Html.fromHtml(parkingList.get(position).getPostTitle()));                    holder.t2.setText(Html.fromHtml(parkingList.get(position).getPostSubTitle()));        
        }        
        @Override
        public int getItemCount() {
            return parkingList.size();
        }        
        public class VH extends RecyclerView.ViewHolder {
            TextView t1, t2;        
            public VH(View view) {
                super(view);        
                t1 = (TextView) view.findViewById(R.id.list_title);
                t2 = (TextView) view.findViewById(R.id.list_desc);        
            }        
        }          
        public void setFilter(List<Post> countryModels) {
            mCountryModel = new ArrayList<>();
            mCountryModel.addAll(countryModels);        
            notifyDataSetChanged();        
        }

    }

回答1:


change your adapter to

public class MyRecAdapter extends RecyclerView.Adapter<MyRecAdapter.VH> {
        public List<Post> parkingList;        
        public Context context;
        ArrayList<Post> mCountryModel;  
        String searchText;

        public MyRecAdapter(List<Post> parkingList, Context context) {
            this.parkingList = parkingList;
            this.context = context;
        }        
        @Override
        public MyRecAdapter.VH onCreateViewHolder(ViewGroup parent, int viewType) {
            return new MyRecAdapter.VH(LayoutInflater.from(parent.getContext()).inflate(R.layout.mycardview, parent, false));
        }        
        @Override
        public void onBindViewHolder(MyRecAdapter.VH holder, int position) {       
                String title = parkingList.get(position).getPostTitle();
                String desc = parkingList.get(position).getPostSubTitle();

                holder.t1.setText(Html.fromHtml(title));                    
                if(searchText.length()>0){
                    //color your text here
                    int index = desc.indexOf(searchText);
                    while(index>0){
                       SpannableStringBuilder sb = new SpannableStringBuilder(desc);
                       ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(158, 158, 158)); //specify color here
                       sb.setSpan(fcs, index, searchText.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); 
                        index = desc.indexOf(searchText,index+1);

                    }
                    holder.t2.setText(sb);  

                }else{
                holder.t2.setText(Html.fromHtml(desc));  
                }

        }        
        @Override
        public int getItemCount() {
            return parkingList.size();
        }        
        public class VH extends RecyclerView.ViewHolder {
            TextView t1, t2;        
            public VH(View view) {
                super(view);        
                t1 = (TextView) view.findViewById(R.id.list_title);
                t2 = (TextView) view.findViewById(R.id.list_desc);        
            }        
        }          
        public void setFilter(List<Post> countryModels,String searchText) {
            mCountryModel = new ArrayList<>();
            mCountryModel.addAll(countryModels);        
            this.searchText = searchText;
            notifyDataSetChanged();        
        }

    }

and set onQueryTextChange to

 @Override
        public boolean onQueryTextChange(String newText) {        

            final List<Post> filteredModelList = filter(list, newText);        
            if (filteredModelList.size() > 0) {        
                myRecAdapter.setFilter(filteredModelList,newText);
                return true;
            } else {
                Toast.makeText(Chapter1.this, "Not Found", Toast.LENGTH_SHORT).show();
                return false;
            }
        }     



回答2:


As per accepted answer indexOf() is not working in case of string value is "Mumbai" same occurrences inside string. So here I have used "Pattern" and "Matcher" class to make it work. Also, I have added ".toLowerCase()" to make string with same case and query work on string as ignore case. If you no need of ignore case of query string, You can remove .toLowerCase() from this code snippet

  SpannableStringBuilder sb = new SpannableStringBuilder(desc);
        Pattern word = Pattern.compile(query.toLowerCase());
        Matcher match = word.matcher(desc.toLowerCase());

        while (match.find()) {
            ForegroundColorSpan fcs = new ForegroundColorSpan(
                    ContextCompat.getColor(context, R.color.colorPrimary)); //specify color here
                sb.setSpan(fcs, match.start(), match.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
        }
        viewHolders.text_view_title.setText(sb);



回答3:


        while(index>**-1**){
                   SpannableStringBuilder sb = new SpannableStringBuilder(desc);
                   ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(158, 158, 158)); //specify color here
                   sb.setSpan(fcs, index, **index** + searchText.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); 
                    index = desc.indexOf(searchText,index+1);

                }

A little add-on to the previous answer , you should check index >-1 instead, else the first text wont be highlighted. For setSpan , the int end should be your index + searchText.length().




回答4:


Use inside on Bind view holder in Adapter class

String title1 = Itemlist.get(position).getN_stall_name().toLowerCase(Locale.getDefault());
            holder.title.setText(Itemlist.get(position).getN_stall_name());

if (title1.contains(searchText)) {
                int startPos = title1.indexOf(searchText);
                int endPos = startPos + searchText.length();
                Spannable spanString = Spannable.Factory.getInstance().newSpannable(holder.title.getText());
                spanString.setSpan(new ForegroundColorSpan(Color.RED), startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                holder.title.setText(spanString);
            }

And now create public method in Adapter class

 public void updateList(List<GetShop> list, String searchText) {
            Itemlist = new ArrayList<>();
            Itemlist.addAll(list);
            this.searchText = searchText;
            notifyDataSetChanged();
        }

Search view listener use inside Activity where you use search view

SearchView searchview=findviewbyid(R.id.searchview);
    searchview.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    return false;
                }
                @Override
                public boolean onQueryTextChange(String newText) {
                    newText = newText.toLowerCase();
                    ArrayList<GetShop> newList = new ArrayList<>();
                    for (GetShop userInfo : items) {
                        String type = userInfo.getN_stall_name().toLowerCase();
                        if (type.contains(newText)) {
                            newList.add(userInfo);
                        }
                    }
                    disp_adapter.updateList(newList, newText);
                    return true;
                }
            });


来源:https://stackoverflow.com/questions/40256605/how-to-highlight-filtered-text-in-recyclerview-when-using-searchview-widget

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!