Highlight a particular word in a String dynamically - android

I want to highlight a particular word in a text view ( more specifically similar to a twitter feed). The word may occur multiple times. Below I will post a sample sentence from twitter.
" Mumbai Master Blaster! #Sachin. Greatest players of all times. The legend of cricket #sachin. "
Here I want to highlight the word " #Sachin " with a particular color. Also please note that we don't know how many times this word could get repeated in the whole string. Could anyone help me to solve this issue.

Use next code:
public CharSequence linkifyHashtags(String text) {
SpannableStringBuilder linkifiedText = new SpannableStringBuilder(text);
Pattern pattern = Pattern.compile("#\\w");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
String hashtag = text.substring(start, end);
ForegroundColorSpan span = new ForegroundColorSpan(Color.BLUE);
linkifiedText.setSpan(span, 0, hashtag.length(), 0);
}
return linkifiedText;
}

Related

How to Bold (Span) the searched text in string dynamically?

I have a string, in which i have to find a word being searched from end user and make it bold to highlight.
Example:
String : Address must have a format. Address can be of multiple line.
Required Text: Address must have a format. Address can be of multiple line.
After going through different Approaches. I have written the following method which will span the searched Text in string.
If you want to span the same text multiple time they can use this method as well.
public CharSequence highlightTextString(String completeText, String searchText) {
String temp = completeText.toLowerCase();
SpannableStringBuilder highlightText = new SpannableStringBuilder(completeText);
Pattern pattern = Pattern.compile(searchText.toLowerCase());
Matcher matcher = pattern.matcher(temp);
while (matcher.find()) {
StyleSpan styleSpan = new StyleSpan(android.graphics.Typeface.BOLD);
highlightText.setSpan(styleSpan, matcher.start(), matcher.end(), 0);
}
return highlightText;
}

Issue with spannable and Ellipsize in TextView

I have a news feed in my app. In a feed item I have a text view which may have url links and hashtags. I need the both the urls and the hashtags to be clickable which is implemented.
protected void setTextClickable(TextView txtView) {
L.i(getClass().getSimpleName(), "SET TEXT CLICKABLE ENTERED" + "LINES: " +String.valueOf(mTextViewLines));
String text = txtView.getText().toString();
ExpandableTextViewClickableSpan clickSpan = null;
ExpandableTextViewClickableSpan clickableSpan = null;
final SpannableString hashTagInText = new SpannableString(text);
String regexURL = "\\(?\\b((http|https)://|www[.])[-A-Za-z0-9+&##/%?=~_()|!:,.;]*[-A-Za-z0-9+&##/%=~_()|]";
String regexHashTag = "#([A-Za-z0-9_-]+)";
Matcher matcherURL = Pattern.compile(regexURL).matcher(hashTagInText);
Matcher matcherHashTag = Pattern.compile(regexHashTag).matcher(hashTagInText);
int color = view.getResources().getColor(R.color.tinted_green_colour);
while (matcherURL.find()) {
clickSpan = new ExpandableTextViewClickableSpan(currentFragment, false, color, hashTagInText,
matcherURL.start(), matcherURL.end(), MenuUtils.sURL_LINKID);
hashTagInText.setSpan(clickSpan, matcherURL.start(), matcherURL.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
while (matcherHashTag.find()) {
clickableSpan = new ExpandableTextViewClickableSpan(currentFragment, false, color, hashTagInText,
matcherHashTag.start(), matcherHashTag.end(), MenuUtils.sHASHTAG_LINKID);
hashTagInText.setSpan(clickableSpan, matcherHashTag.start(), matcherHashTag.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
However, there is also the requirement that if the message is longer than 4 lines then I ellipsis and show a view more/less option.
Since introducing the method to colour and set clickable the urls and hashtags (which works with spannables which then renders the ellipsis ineffective).
So now my ellipsis doesn't work. I came across this Spannable Ellipsis Issue on SO. However this requires a line count which I can't get unless it's done in a global layout listener.
Which I have done and successfully get the line count. The problem is however that the bind data method is called in which the spannable is applied and layout populated (where I want to apply my own ellipsis method) before the onGlobalLayout method is called, which then leaves me with 0 line count.
Is there a simple way to combine both ellipsis and spannable? Any help is appreciated.

Android BreakIterator hyphenated words?

I using breakIterator to get each word from a sentence and there is problem when a sentence like "my mother-in-law is coming for a visit" where i am not able to get mother-in-law as a single word.
BreakIterator iterator = BreakIterator.getWordInstance(Locale.ENGLISH);
for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator.next())
{
String possibleWord = sentence.substring(start, end);
if (Character.isLetterOrDigit(possibleWord.charAt(0)))
{
// grab the word
}
}
As I'm seeing in your code what are you trying to do is to check if the first character in every word are a character or a digit. Every time you use the BreakIterator.getWordInstance() you will always get all the words depending on the boundary rules of the Locale and it is a little hard to accomplish what you want to do with the use of this class until I know, so my advice is this:
String text = "my mother-in-law is coming for a visit";
String[] words = text.split(" ");
for (String word : words){
if (Character.isLetterOrDigit(word.charAt(0))){
// grab the word
}
}

Android: Highlight search query in results like Apple's notes.app

I am new to Android. I use an iPhone, so I am not just new to the programming, but also to the OS completely. I just started this week and have written a basic notes application.
Now, when I go to the search view, search say "cats", if a result appears and I click to go to that note, I want all instances of "cats" to be highlighted. Then, when I tap in the EditText, I want the highlighting to go away.
It would also be awesome if I could highlight the text within the search view.
Apple's Notes.app does this and I think it really adds to the search functionality. Couldn't find any images to show you what I mean. Hopefully I explained it well enough.
I tried this:
//highlight searched text
//Get the text of the EditText
String text = editText.getText().toString();
//Get indexes of the query in the EditText
int firstIndex = text.indexOf(query);
int lastIndex = text.lastIndexOf(query);
//Highlight the selection
editText.setSelection(firstIndex, lastIndex);
But we run into problems if there are multiple of the same word. Any thoughts?
Selection and highlighting are not the same thing. Usually, selecting something also highlights it, but you don't highlight something by selecting it. Besides, Android does not support multiple selection in EditText.
To highlight, you need to apply a CharacterStyle to the range of text, such as a BackgroundColorSpan.
This sample project applies a BackgroundColorSpan to highlight search results in a TextView, using:
private void searchFor(String text) {
TextView prose=(TextView)findViewById(R.id.prose);
Spannable raw=new SpannableString(prose.getText());
BackgroundColorSpan[] spans=raw.getSpans(0,
raw.length(),
BackgroundColorSpan.class);
for (BackgroundColorSpan span : spans) {
raw.removeSpan(span);
}
int index=TextUtils.indexOf(raw, text);
while (index >= 0) {
raw.setSpan(new BackgroundColorSpan(0xFF8B008B), index, index
+ text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
index=TextUtils.indexOf(raw, text, index + text.length());
}
prose.setText(raw);
}
The code shown first removes any existing BackgroundColorSpan instances, then applies new ones based on a search string.
Since EditText inherits from TextView, the same basic concept would apply here. However, IMHO, doing this sort of highlighting in an EditText will be foreign to users. I'd show the search results in a plain TextView, with an "edit" action bar item or something to move into editing mode.
I did some googling and looked searching "java" instead of "android" was helpful. Below is my working code:
private void highlightIndexes(String query){
String text = editText.getText().toString();
Map<Integer, Integer> indexMap = getIndexes(query);
Spannable spannable=new SpannableString(text);
Iterator<Integer> keySetIterator = indexMap.keySet().iterator();
while(keySetIterator.hasNext()){
Integer key = keySetIterator.next();
Integer value = indexMap.get(key);
spannable.setSpan(new ForegroundColorSpan(Color.BLUE), key, value, 0);
}
editText.setText(spannable);
}
private Map<Integer, Integer> getIndexes(String query){
Map<Integer, Integer> indexMap = new TreeMap<Integer, Integer>();
int queryLength = query.length();
query = query.substring(0, (queryLength -1)).toLowerCase(Locale.US);
String text = editText.getText().toString().toLowerCase(Locale.US);
int i, y;
i = text.indexOf(query);
y = i + queryLength - 1;
indexMap.put(i, y);
while(i >= 0) {
i = text.indexOf(query, i+1);
y = i + queryLength - 1;
if (i != -1 && y != -1){
indexMap.put(i, y);
}
}

Highlight multiple words in a string using SpannableString

I'm using a SpannableString to underline certain words, however, I realized the code I have only highlights the first word if there are multiple words. Not exactly sure how to accomplish highlighting multiple words:
String keyword = "test";
String text = "This is a test to underline the three test words in this test";
SpannableString output = new SpannableString(text);
if (text.indexOf(keyword) > -1)
{
int keywordIndex = text.indexOf(keyword);
int keywordLength = keyword.length();
int start = keywordIndex;
int end = keywordIndex + (keywordLength);
output.setSpan(new UnderlineSpan(), start, end, 0);
}
I was thinking I could split the text at every space and loop through it, but wasn't sure if there was a better way.
I do have this code to highlight multiple words using a regular expression, however, I'm try to avoid regular expressions since it's in an Android app and I'm using it in a ListView and I'm told they are very expensive. Also this code I have only highlight whole words, so using the example text above, if the word "protest" was in the sentence, it wouldn't get highlighted using this code:
Matcher matcher = Pattern.compile("\\b(?:test")\\b").matcher(text);
while (matcher.find())
{
output.setSpan(new UnderlineSpan(), matcher.start(), matcher.end(), 0);
}

Categories

Resources