36

I have a database search query which search in the database for a word entered by the user and return a Cursor.

In my ListActivity, I have a ListView which will hold the items (the Cursor items). The ListView items layout is basically a TextView. I mean, the ListView will be a list of TextView's.

What I want is to highlight the search term wherever it appears in the TextView. I mean by highlighting: different color or different background color or anything makes it different than the rest of the text.

Is this possible? and how?

Update:

cursor = myDbHelper.search(term);  //term: a word entered by the user.
cursor.moveToFirst();
String[] columns = {cursor.getColumnName(1)}; 
int[] columnsLayouts = {R.id.item_title}; //item_title: the TextView holding the one raw
ca = new SimpleCursorAdapter(this.getBaseContext(), R.layout.items_layout, cursor,columns , columnsLayouts);
lv = getListView();
lv.setAdapter(ca);

For @Shailendra: The search() method will return some titles. I want to highlight the words in those titles that matches the term word. I hope this is clear now.

iTurki
  • 16,292
  • 20
  • 87
  • 132

9 Answers9

44

insert HTML code for color around word and set it to your textView .

like

String newString = oldString.replaceAll(textToHighlight, "<font color='red'>"+textToHighlight+"</font>");
textView.setText(Html.fromHtml(newString));
Shailendra Singh Rajawat
  • 8,172
  • 3
  • 35
  • 40
  • The problem is that it isn't a simple one TextView which holds a text. It is a ListView which holds the query results (may be 1 or more results. So, may be a one TextView or more). So, I doubt that I can change the text in this list by this way, Can I? – iTurki Jul 27 '11 at 11:56
  • so ?? i can't see any problem regarding text inside listview ...... can you elaborate your problem a bit more ??? – Shailendra Singh Rajawat Jul 27 '11 at 12:07
  • 1
    here you are using SimpleCursorAdapter which will set Text of respective colum to TextView R.id.item_title . so make customAdapter which will extend SimpleCursorAdapter . pass String term to it and write above replaceAll code into getView overridden method – Shailendra Singh Rajawat Jul 27 '11 at 12:35
  • I'll try it and get back to here :) – iTurki Jul 27 '11 at 16:07
  • If the user type in html tag, wouldn't they be able to do funny things to the text? – CodeGuru May 28 '15 at 14:09
  • Working in android 10 & 11. But not working in android 7 – Abu Saeed Jan 08 '22 at 17:27
25
TextView textView = (TextView)findViewById(R.id.mytextview01);

//use a loop to change text color
Spannable WordtoSpan = new SpannableString("partial colored text");        
WordtoSpan.setSpan(new ForegroundColorSpan(Color.BLUE), 2, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(WordtoSpan);

The numbers 2 and 4 are start/stop indexes for the coloring of the text, in this example "rti" would be colored.

So you would basically just find the starting index of your searching word in the title:

int startIndex = titleText.indexOf(term);
int stopIndex = startIndex + term.length();

and then replace the numbers 2 and 4 with the indexes and "partial colored text" with your title string.

source: https://stackoverflow.com/a/10279703/2160827

Community
  • 1
  • 1
finstas
  • 319
  • 3
  • 5
8

More Easy Way

You can use Spannable class for highlighting/formatting part of Text.

textView.setText("Hello, I am Awesome, Most Awesome"); // set text first
setHighLightedText(textView, "a"); // highlight all `a` in TextView

Output

Here is the method.

 /**
     * use this method to highlight a text in TextView
     *
     * @param tv              TextView or Edittext or Button (or derived from TextView)
     * @param textToHighlight Text to highlight
     */
    public void setHighLightedText(TextView tv, String textToHighlight) {
        String tvt = tv.getText().toString();
        int ofe = tvt.indexOf(textToHighlight, 0);
        Spannable wordToSpan = new SpannableString(tv.getText());
        for (int ofs = 0; ofs < tvt.length() && ofe != -1; ofs = ofe + 1) {
            ofe = tvt.indexOf(textToHighlight, ofs);
            if (ofe == -1)
                break;
            else {
                // set color here
                wordToSpan.setSpan(new BackgroundColorSpan(0xFFFFFF00), ofe, ofe + textToHighlight.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                tv.setText(wordToSpan, TextView.BufferType.SPANNABLE);
            }
        }
    }

You can check this answer for clickable highlighted text.

Community
  • 1
  • 1
Khemraj Sharma
  • 57,232
  • 27
  • 203
  • 212
5

I know it's old question but i have created a method to highlight a repeated-word in string\paragraph.

private Spannable highlight(int color, Spannable original, String word) {
    String normalized = Normalizer.normalize(original, Normalizer.Form.NFD)
            .replaceAll("\\p{InCombiningDiacriticalMarks}+", "");

    int start = normalized.indexOf(word);
    if (start < 0) {
        return original;
    } else {
        Spannable highlighted = new SpannableString(original);
        while (start >= 0) {
            int spanStart = Math.min(start, original.length());
            int spanEnd = Math.min(start+word.length(), original.length());

            highlighted.setSpan(new ForegroundColorSpan(color), spanStart,
                    spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

            start = normalizedText.indexOf(word, spanEnd);
        }
        return highlighted;
    }
}

usage:

textView.setText(highlight(primaryColor, textAll, wordToHighlight));
Sumit
  • 1,022
  • 13
  • 19
5

Based on the previous answers I developed the following function, you can copy/paste it

 private void highlightMask(TextView textView, String text, String mask) {
            boolean highlightenabled = true;
            boolean isHighlighted = false;

            if (highlightenabled) {
                if (!TextUtils.isEmpty(text) && !TextUtils.isEmpty(mask)) {
                    String textLC = text.toLowerCase();
                    mask = mask.toLowerCase();

                    if (textLC.contains(mask)) {
                        int ofe = textLC.indexOf(mask, 0);
                        Spannable wordToSpan = new SpannableString(text);
                        for (int ofs = 0; ofs < textLC.length() && ofe != -1; ofs = ofe + 1) {
                            ofe = textLC.indexOf(mask, ofs);
                            if (ofe == -1) {
                                break;
                            } else {
                                // set color here
                                wordToSpan.setSpan(new BackgroundColorSpan(0xFFFFFF00), ofe, ofe + mask.length(),
                                                   Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                                textView.setText(wordToSpan, TextView.BufferType.SPANNABLE);
                                isHighlighted = true;
                            }
                        }

                    }
                }
            }

            if (!isHighlighted) {
                textView.setText(text);
            }
        }
Szabolcs Becze
  • 507
  • 1
  • 5
  • 10
2

I haven't done it but this looks promising:

http://developer.android.com/reference/android/text/SpannableString.html
http://developer.android.com/guide/topics/resources/string-resource.html

public final void setText (CharSequence text)

Since: API Level 1 Sets the string value of the TextView. TextView does not accept HTML-like formatting, which you can do with text strings in XML resource files. To style your strings, attach android.text.style.* objects to a SpannableString, or see the Available Resource Types documentation for an example of setting formatted text in the XML resource file.

http://developer.android.com/reference/android/widget/TextView.html

Tim
  • 5,371
  • 3
  • 32
  • 41
1

Try this library Android TextHighlighter.

Implementations

TextView.setText() gets a parameter as Spannable not only CharacterSequence. SpannableString has a method setSpan() which allows applying styles.

See list of direct subclass form CharacterStyle https://developer.android.com/reference/android/text/style/CharacterStyle.html

  • example of giving background color and foreground color for word "Hello" in "Hello, World"
Spannable spannable = new SpannableString("Hello, World");
// setting red foreground color
ForegroundSpan fgSpan = new ForegroundColorSpan(Color.red);
// setting blue background color
BackgroundSpan bgSpan = new BackgroundColorSPan(Color.blue);

// setSpan requires start and end index
// in our case, it's 0 and 5
// You can directly set fgSpan or bgSpan, however,
// to reuse defined CharacterStyle, use CharacterStyle.wrap()
spannable.setSpan(CharacterStyle.wrap(fgSpan), 0, 5, 0);
spannable.setSpan(CharacterStyle.wrap(bgSpan), 0, 5, 0);

// apply spannableString on textview
textView.setText(spannable);
xeoh
  • 21
  • 3
  • 1
    To use the library, add to gradle: `compile 'com.xeoh.android:text-highlighter:1.0.1'` (but your example code is not for the library) – gregn3 Sep 10 '17 at 00:02
1

You do so in xml strings if your strings are static

<string name="my_text">This text is <font color='red'>red here</font></string>
Isaac Sekamatte
  • 5,500
  • 1
  • 34
  • 40
1

I know this thread is old, but just in case anyone is looking to highlight strings in a textview, I have created a library that does exactly this. This is my first answer to a question on stack overflow, as I have just joined, hopefully it's formatted properly and relevant. It uses SpannableString and will locate all occurrences of a string you specify. Additionally, a custom ClickableSpan is built in giving you the option to set up listeners for text clicked if desired.

Linker

Lightweight android library for highlighting Strings inside of a textview (ignoring case), with optional callbacks.

Language: Java

MinSDK: 17

An image of it's functionality and all of the code can be found here.

JavaDocs

To bring into your android project implement the artifact:

In the Project level build.gradle

    allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

In the App level build.gradle

       dependencies {
            implementation 'com.github.Gaineyj0349:Linker:1.2'
    }

How to use:

1 - Construct a Linker object with a textview:

        Linker linker = new Linker(textView);

2 - Add an array or a list of strings to be highlighted within the textview's text:

        ArrayList<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");
        linker.addStrings(list);

AND/OR

        String[] words = new String[]{"One", "Two", "Three"};
        linker.addStrings(words);

3 - Add a callback: (this is optional):

       linker.setListener(new LinkerListener() {
            @Override
            public void onLinkClick(String charSequenceClicked) {

                // charSequenceClicked is the word that was clicked

                Toast.makeText(MainActivity.this, charSequenceClicked, Toast.LENGTH_SHORT).show();
            }
        });

4 - Call the linker's update method to commit customization and rollout the setup.:

        linker.update();

You always have the option to add Strings to the linker object, just make sure you call the update method after to refresh the spans.

    linker.addStrings("yoda");
    linker.update();

If you need a fresh slate with same linker object just call

       linker.clearLinksList()

You can customize the links also:

1 - Customize all the link colors:

      linker.setAllLinkColors(Color.BLUE);

2 - Customize link underlines:

      linker.setAllLinkUnderline(false);

3 - If you wish to customize a color or underline setting for a certain string (note the string must already be added to the linker):

      linker.setLinkColorForCharSequence("world", Color.MAGENTA);
      linker.setUnderlineModeForCharSequence("world", true);

4 - If you wish to use different setups for every word then you can also give the linker object a list or array of LinkProfiles:

        ArrayList<LinkProfile> profiles = new ArrayList<>();
        profiles.add(new LinkProfile("hello world",
                Color.GREEN, false));
        profiles.add(new LinkProfile("goodbye cruel world",
                Color.RED, false));
        profiles.add(new LinkProfile("Whoa awesome!",
                Color.CYAN, true));


        linker.addProfiles(profiles);

Just remember to call .update() after any additions to the linker object.

Note that the library will take care of subtleties like adding two of the same words, or same parts of a word. For example if "helloworld" and "hello" are two of the words added to the linker, "helloworld" will be given preference over "hello" when they are in the same span of characters. The linker will sort according to larger words first and trace all spans as it links them - avoiding the issue of duplication as well as intersecting spans.

Licensed under MIT license .

Joshua Gainey
  • 311
  • 3
  • 4