Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Spannable multiple setSpan in one TextView

Tags:

android

I'm developing a simple search box in my application, and I want to highlight multiple words in one sentence.

I use SpannableString to add multiple span in one sentence. Here the function a wrote

private CharSequence highlightText(String text, String query) {
    if (query != null && !query.isEmpty()) {

        Spannable spannable = new SpannableString(text);
        ForegroundColorSpan highlightSpan = new ForegroundColorSpan(Color.BLUE);

        String[] queryParts = query.split(" ");
        for (String queryPart : queryParts) {
            int startPos = text.toLowerCase(Locale.US).indexOf(queryPart.toLowerCase(Locale.US));
            int endPos = startPos + queryPart.length();

            if (startPos != -1) {
                Log.d(TAG, "find: '" + queryPart + "' in '" + text + "' (" + startPos + ")");
                spannable.setSpan(highlightSpan, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
        return spannable;

    } else {
        return text;
    }
}

When I cal this function with

TextView spannableTest = findViewById(R.id.spannable_test);
spannableTest.setText(highlightText(
            "Lorem ipsum dolor sit amet, consectetur adipisicing elit.",
            "ipsum consect"));

I got this logs

 D/SPAN: find: 'ipsum' in 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' (6)
 D/SPAN: find: 'consect' in 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' (28)

But on result screen only the last occurence is realy highlighted

Result image

like image 816
Yoann Avatar asked Mar 19 '18 09:03

Yoann


2 Answers

@pskink pointed I should move ForegroundColorSpan highlightSpan = new ForegroundColorSpan(Color.BLUE); to for loop.

like image 195
Yoann Avatar answered Oct 24 '22 09:10

Yoann


Add this file to your project:RichTextView.java

package com.outpace.expert.utility;

import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.URLSpan;
import android.view.View;

/**
 * Created by Deep Patel on 19-11-16
 */

//.setText(text, TextView.BufferType.SPANNABLE); to textView if not work
public class RichTextView extends SpannableString {
    private String syntax;

    public RichTextView(String syntax) {
        super(syntax);
        this.syntax = syntax;
    }

    public RichTextView setTextColor(String word, int color) {
        setSpan(new ForegroundColorSpan(color), syntax.indexOf(word), syntax.indexOf(word) + word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return this;
    }

    public RichTextView setSize(String word, float howMuch) {
        setSpan(new RelativeSizeSpan(howMuch), syntax.indexOf(word), syntax.indexOf(word) + word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return this;
    }

    public RichTextView setStrikeOut(String word) {
        setSpan(new StrikethroughSpan(), syntax.indexOf(word), syntax.indexOf(word) + word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return this;
    }

    public RichTextView setUrl(String word, String redirectUrl) {
        setSpan(new URLSpan(redirectUrl), syntax.indexOf(word), syntax.indexOf(word) + word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return this;
    }

    public RichTextView setBold(String word) {
        StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
        setSpan(boldSpan, syntax.indexOf(word), syntax.indexOf(word) + word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return this;
    }

    //setMovementMethod(LinkMovementMethod.getInstance()); after or before call
    public RichTextView setClickable(String word, final setOnLinkClickListener listener) {
        ClickableSpan clickableSpan = new ClickableSpan() {
            @Override
            public void onClick(View view) {
                if (listener != null) {
                    listener.onLinkClicked();
                }
            }
        };
        setSpan(clickableSpan, syntax.indexOf(word), syntax.indexOf(word) + word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return this;
    }

    public interface setOnLinkClickListener {
        void onLinkClicked();
    }
}

Here is how to use:

String data = model.getMessage().replace("{from_name}", model.getFromUser()); // String to display

tvNotificationText.setText(new RichTextView(data)
                    .setBold(model.getFromUser())    // bold 
                    .setTextColor(model.getFromUser(), ContextCompat.getColor(mContext, R.color.textPrimary))); // set text color for specific string

There are other spanning options available please explore and get the best fit solution!

Happy Coding !!

like image 20
Deep Patel Avatar answered Oct 24 '22 11:10

Deep Patel