I am trying to do a search such that all the \"visible\" search letters should be highlighted. I tried using spannable but that didn\'t do the trick, maybe I wasnt doing it
Put this code before setting text in getview
Spannable wordtoSpan = new SpannableString("Your_text_in_getviews");
wordtoSpan.setSpan(new ForegroundColorSpan(Color.RED), 0, edtFilter
.getText().toString().length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
txt_contact.setText(wordtoSpan);
Let's assume you have create a custom adapter, then you can refer to the following code:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
TextView text;
if (convertView == null) {
view = mInflater.inflate(mResource, parent, false);
} else {
view = convertView;
}
try {
if (mFieldId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = (TextView) view.findViewById(mFieldId);
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e);
}
String item = getItem(position);
text.setText(item);
String fullText = getItem(position);
// highlight search text
if (mSearchText != null && !mSearchText.isEmpty()) {
int startPos = fullText.toLowerCase(Locale.US).indexOf(mSearchText.toLowerCase(Locale.US));
int endPos = startPos + mSearchText.length();
if (startPos != -1) {
Spannable spannable = new SpannableString(fullText);
ColorStateList blueColor = new ColorStateList(new int[][]{new int[]{}}, new int[]{Color.BLUE});
TextAppearanceSpan highlightSpan = new TextAppearanceSpan(null, Typeface.BOLD, -1, blueColor, null);
spannable.setSpan(highlightSpan, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setText(spannable);
} else {
text.setText(fullText);
}
} else {
text.setText(fullText);
}
return view;
}
The mSearchText
will be updated at the following inside performFiltering
of ArrayFilter
class.
String prefixString = prefix.toString().toLowerCase();
mSearchText = prefixString;
You can find more details in my sample code here or my GitHub (with lastest update).
Here is the screenshot
In your filter method, store the string used to perform the filter:
// Filter Class
public void filter(String searchString) {
this.searchString = searchString;
...
// Filtering stuff as normal.
}
You must declare a member string to store it:
public class ListViewAdapter extends BaseAdapter {
...
String searchString = "";
...
And, in getView you highlight the search term:
public View getView(final int position, View view, ViewGroup parent) {
...
// Set the results into TextViews
WorldPopulation item = worldpopulationlist.get(position);
holder.rank.setText(item.getRank());
holder.country.setText(item.getCountry());
holder.population.setText(item.getPopulation());
// Find charText in wp
String country = item.getCountry().toLowerCase(Locale.getDefault());
if (country.contains(searchString)) {
Log.e("test", country + " contains: " + searchString);
int startPos = country.indexOf(searchString);
int endPos = startPos + searchString.length();
Spannable spanText = Spannable.Factory.getInstance().newSpannable(holder.country.getText()); // <- EDITED: Use the original string, as `country` has been converted to lowercase.
spanText.setSpan(new ForegroundColorSpan(Color.RED), startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.country.setText(spanText, TextView.BufferType.SPANNABLE);
}
...
}
Hope it helps.
Hi on your adapter class ,make a spanneble text and set it to your textview, the below code you can use for reference.
if ("text contains filter value".toLowerCase().contains("filter".toLowerCase())) {
Spannable spanText = Spannable.Factory.getInstance().newSpannable("text contains filter value".toLowerCase());
Matcher matcher = Pattern.compile("filter".toLowerCase())
.matcher("text contains filter value".toLowerCase());
while (matcher.find()) {
spanText.setSpan(new ForegroundColorSpan(Color.RED), matcher.start(),
matcher.start() + "filter".length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
yourTextView.setText(spanText);
}
This is only demo for highlight text, you can implement your self by calling
highlight(searchText, originalText)
in filter,
public class MainActivity extends AppCompatActivity {
EditText editText;
TextView text;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText);
text = (TextView) findViewById(R.id.textView1);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
text.setText(highlight(editText.getText().toString(), text.getText().toString()));
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
public static CharSequence highlight(String search, String originalText) {
String normalizedText = Normalizer.normalize(originalText, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "").toLowerCase();
int start = normalizedText.indexOf(search);
if (start <= 0) {
return originalText;
} else {
Spannable highlighted = new SpannableString(originalText);
while (start > 0) {
int spanStart = Math.min(start, originalText.length());
int spanEnd = Math.min(start + search.length(), originalText.length());
highlighted.setSpan(new BackgroundColorSpan(Color.YELLOW), spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = normalizedText.indexOf(search, spanEnd);
}
return highlighted;
}
}
}