10

I tried this:

String s = "Some big string"
SpannableStringBuilder sb = new SpannableStringBuilder(s);
//normal font for 1st 9 chars
sb.setSpan(robotoRegular, 0,9,Spannable.SPAN_INCLUSIVE_INCLUSIVE);
//bold font for rest of the chars
sb.setSpan(robotoBold, 9,s.length(),Spannable.SPAN_INCLUSIVE_INCLUSIVE);
//also change color for rest of the chars
sb.setSpan(new ForegroundColorSpan(Color.BLACK), 9,s.length(),Spannable.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(sb);

But this didn't work.

It only takes the latest setSpan, ie.., the Text color is being changed but not the font.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Archie.bpgc
  • 23,812
  • 38
  • 150
  • 226

4 Answers4

37

You have to use a TypefaceSpan instead of a Typeface.

But since you are using a custom typeface you need to extend TypefaceSpan.

Check out this answer and create CustomTypefaceSpan class.

Now do the following:

Typeface robotoRegular = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf");
Typeface robotoBold = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Bold.ttf");

TypefaceSpan robotoRegularSpan = new CustomTypefaceSpan("", robotoRegular);
TypefaceSpan robotoBoldSpan = new CustomTypefaceSpan("", robotoBold);

// normal font for 1st 9 chars
sb.setSpan(robotoRegularSpan, 0, 9, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
// bold font for rest of the chars
sb.setSpan(robotoBoldSpan, 9, s.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
// also change color for rest of the chars
sb.setSpan(new ForegroundColorSpan(Color.BLUE), 9, s.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(sb);
Community
  • 1
  • 1
Benito Bertoli
  • 25,285
  • 12
  • 54
  • 61
2

For peaple who prefer to make utils classes for this:

public static SpannableStringBuilder makeTextBold (Activity activity, String string, int fromCharIndex, int toCharIndex) {
    return makeTextBold(activity, new SpannableStringBuilder(string), fromCharIndex, toCharIndex);
}

public static SpannableStringBuilder makeTextBold (Activity activity, SpannableStringBuilder string, int fromCharIndex, int toCharIndex) {
    SpannableStringBuilder sb = new SpannableStringBuilder(string);
    Typeface bold = Typeface.createFromAsset(activity.getAssets(), "fonts/NexaBold.ttf");
    TypefaceSpan robotoBoldSpan = new CustomTypefaceSpan("", bold);
    sb.setSpan(robotoBoldSpan, fromCharIndex, toCharIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
    return sb;
}

public static SpannableStringBuilder colorText (int resourceId, String string, Activity activity, int fromCharIndex, int toCharIndex) {
    return colorText(resourceId, new SpannableStringBuilder(string), activity, fromCharIndex, toCharIndex);
}

public static SpannableStringBuilder colorText (int resourceId, SpannableStringBuilder sb, Activity activity, int fromCharIndex, int toCharIndex) {
    sb.setSpan(new ForegroundColorSpan(activity.getResources().getColor(resourceId)), fromCharIndex, toCharIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
    return sb;
}
jobbert
  • 3,297
  • 27
  • 43
0

check this code :-

protected void onDraw(Canvas canvas) {

        Paint circlePaint = new Paint();
        Typeface mType = Typeface.create(Typeface.SANS_SERIF, Typeface.ITALIC);
        circlePaint.setTextSize(25);
        circlePaint.setColor(Color.RED);
        circlePaint.setTypeface(mType);
        canvas.drawText("Default Typeface", 50, 100, circlePaint);
        //
        circlePaint.setFlags(Paint.UNDERLINE_TEXT_FLAG);
        circlePaint.setColor(Color.YELLOW);
        canvas.drawText("Underline Text Flag", 50, 120, circlePaint);
        //
        circlePaint.setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
        circlePaint.setColor(Color.GREEN);
        canvas.drawText("Strike Thru Text Flag", 50, 140, circlePaint);
        //
        circlePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        circlePaint.setColor(Color.WHITE);
        canvas.drawText("Anti Alias Flag", 50, 160, circlePaint);
        //
        circlePaint.setFlags(Paint.DEV_KERN_TEXT_FLAG);
        circlePaint.setColor(Color.WHITE);
        canvas.drawText("Dev Kern Text Flag", 50, 180, circlePaint);
        //
        circlePaint.setFlags(Paint.FAKE_BOLD_TEXT_FLAG);
        circlePaint.setColor(Color.CYAN);
        canvas.drawText("Fake Bold Text Flag", 50, 200, circlePaint);
    }
Android
  • 2,383
  • 1
  • 26
  • 44
0

Google actually gave an official answer about this on this video:

Also you can follow the docs explaining it as well

Please be aware that this approach is just Android P+ compatible and strings cannot be formatted (using %1$s params)

strings.xml

    <string name="test">Hello <annotation font="sans-serif-medium">World!</annotation></string>

And in code:

val spanned = context.getText(R.string.title) as SpannedString
val spannable = SpannableString(spanned)
spanned.getSpans(0, spanned.length, Annotation::class.java).filter { annotation ->
  annotation.key == "font"
}.forEach { annotation ->
  val typeface = Typeface.create(annotation.value, Typeface.NORMAL)
  spannable.setSpan(TypefaceSpan(typeface),
    spanned.getSpanStart(annotation),
    spanned.getSpanEnd(annotation),
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
textView.text = spannable
Rubén Viguera
  • 3,277
  • 1
  • 17
  • 31
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • I am looking for marking portions of a `String` using `annotation` programmatically .. appreciate if you can help in this – Zain Jan 10 '21 at 14:21
  • 1
    @Zain If you do this programmatically , you don't need annotation. You just set the span according to the positions you need. – android developer Jan 10 '21 at 14:30
  • thanks for instant feedback.. I need to do something customized that I have to use custom `ReplacementSpan` in it .. the problem is that it doesn't support multi-lined text unless using annotations – Zain Jan 10 '21 at 14:38
  • @Zain Sorry but I didn't use it much. If you wish, I've made a sample of highlighting text within some string, programmatically, here: https://stackoverflow.com/a/57534078/878126 . – android developer Jan 10 '21 at 15:02
  • 1
    I have edited your answer to fill the gaps on your original one – Rubén Viguera May 09 '22 at 11:17