ivan ivan - 2 days ago 4
Android Question

How to highlight filtered text in RecyclerView when using SearchView widget

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();
}

}

Answer

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;
            }
        }     
Comments