I have styles (e.g., BackgroundColorSpan) and I'd like to set it to multiple parts of the texts. But if the same instance of BackgroundColorSpan, etc. is assigned to other part of the text, the style moves.
E.g.,
Object HighlightStyle = new BackgroundColorSpan(Color.argb(255, 255, 215, 0));
TextView X = (TextView) findViewById(R.id.Text);
SpannableStringBuilder SpannableBuilder = new SpannableStringBuilder();
SpannableBuilder.append("1");
SpannableBuilder.setSpan(HighlightStyle, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // This is hilited
SpannableBuilder.append("2");
SpannableBuilder.setSpan(HighlightStyle, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // This is hilited and 1 is no more hilited
SpannableBuilder.append("3");
SpannableBuilder.append("4");
SpannableBuilder.setSpan(HighlightStyle, 3, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // This is hilited and 1 and 2 are no more hilited
X.setText(SpannableBuilder);
// I want hilited 1,2,4 all at the same time
Why I do it ? A user can search for some text and that text should be highlighted.
How I'd like to do it ? All text is in a single TextView. I have a single SpannableStringBuilder. I have a method that breaks the text into parts - String and Boolean. String is part, Boolean says whether the text is matched - should be highligted - or not. I just pass, e.g., instance of BackgroundColorSpan into that method and it should be applied to every part that was matched but because of the behavior of setSpan, only last part is highlighted.
Potential solutions: Style doesn't implement .clone method. I could make a workaround like serialize/deserialize it to create new instances but that seems really like a hack.
Is there some elegant way how to set the same style to X parts of the text ?
You should create new HighlightStyle object each time when you call setSpan(), you can do this with the next method:
CharacterStyle.wrap()
With all changes your code will be the next:
SpannableStringBuilder SpannableBuilder = new SpannableStringBuilder();
SpannableBuilder.append("1");
SpannableBuilder.setSpan(CharacterStyle.wrap(HighlightStyle), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
SpannableBuilder.append("2");
SpannableBuilder.setSpan(CharacterStyle.wrap(HighlightStyle), 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
SpannableBuilder.append("3");
SpannableBuilder.append("4");
SpannableBuilder.setSpan(CharacterStyle.wrap(HighlightStyle), 3, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
This is how it looks in my Application:
Related
I am trying to use the SpannableStringBuilder to implement spannable color to all occurrence of a given character sequence in the sentence, just like:
val spannableStr1 = SpannableString("hello world!")
spannableStr1.setSpan(ForegroundColorSpan(Color.parseColor("#FF0000")),
0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
val spannableBuilder = SpannableStringBuilder()
spannableBuilder.append(spannableStr1)
spannableBuilder.append(spannableStr1)
tvDemo.text = spannableBuilder
and this resulted to:
I need the second occurrence of the characters hel also in red color. So I tried to append spannableStr1 again, but it seems not working.
Is there any way to implement it?
The span on spannableStr1 is set for 0-3. Unfortunately once you add it to the spannable string builder the second time, it's still 0-3. This causes the problem here- you colored the same part red twice.
A better way of doing this is not to add spans to the text. Instead, just append the text and add the spans directly to the SpannableStringBuilder. This means the first span should be (0,3) and the second one should be (index of second h, index of second h + 3)
val spannableStr1 ="hello world!"
val spannableBuilder = SpannableStringBuilder()
spannableBuilder.append(spannableStr1)
spannableBuilder.append(spannableStr1)
spannableBuilder.setSpan(ForegroundColorSpan(Color.parseColor("#FF0000")),
0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
spannableBuilder.setSpan(ForegroundColorSpan(Color.parseColor("#FF0000")),
spannableStr1.length, spannableStr1.length + 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
tvDemo.text = spannableBuilder
I have a string with some points which i get from storage model , I want to bold and color the point string only which i get from data storage model. How do i do that i have tried below mentioned code.
//Making a part of text from terms and condition spannable
SpannableStringBuilder sb = new SpannableStringBuilder("App " + CWalletDataModel.getInstance().getS_szWalletBalance() + getString(R.string.points_text));
// Span to set text color to some RGB value
final ForegroundColorSpan fcs = new ForegroundColorSpan(RewardUtil.getColor(mContext,R.color.colorAccent));
// create a bold StyleSpan to be used on the SpannableStringBuilder
StyleSpan b = new StyleSpan(Typeface.BOLD); // Span to make text bold
// Set the text color for first 4 characters
sb.setSpan(fcs, 8, 8 + CWalletDataModel.getInstance().getS_szWalletBalance().length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
// set only the name part of the SpannableStringBuilder to be bold --> 16, 16 + name.length()
sb.setSpan(b, 8, 8 + CWalletDataModel.getInstance().getS_szWalletBalance().length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold
HomeScreenActivity.m_toolbarTitle.setText(sb);
Here i want only to bold "CWalletDataModel.getInstance().getS_szWalletBalance()".
That's because App + blank space is 4 characters("App "), not 8. Set the start for those 5000 at 4th position like you wrote in the comment and then spannable options would start after "App "
sb.setSpan(fcs, 4, 4 + test.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(b, 4, 4 + test.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
So, i'm having a message which contains text and SpannableStringBuilder which is initialized like this :
final SpannableStringBuilder builder = new SpannableStringBuilder(message.getMessage());
And by default, i'm setting font to BOLD :
builder.setSpan(new StyleSpan(Typeface.BOLD), 0, messageText.length(), 0);
But my message text will be changed, example :
Your question : {question}
Your answer : {answer}
{question} and {answer} are objects that will be replaced with text, replacing is happening like this:
final TextObject question = objects.getQuestion();
spannable = new SpannableString(question.getText());
spannable.setSpan(new StyleSpan(Typeface.NORMAL), 0, spannable.length(), 0);
builder.replace(start, end, spannable);
Text is replacing just fine, but NORMAL font type isn't applying to it, so i have all text BOLD, but i need this parts to be normal
Any help is highly appreciated
You have to add that Spanned.SPAN_INCLUSIVE_INCLUSIVE as a last parameter
spannable.setSpan(new StyleSpan(Typeface.NORMAL), 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
and if you want some part in bold and some not you have to be specific which part. The second and the third parameter of setSpan method is responsible for that
I'm trying to display a log file in a textview, but the tab characters I have in the file aren't displaying properly.
SpannableStringBuilder span = new SpannableStringBuilder(text);
span.setSpan(new TabStopSpan.Standard(600), 0, span.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
((TextView) findViewById(R.id.logText)).setText(span, TextView.BufferType.SPANNABLE);
What happens is that the first tab in a line displays properly, but all subsequent tabs show up as spaces. I have tried replacing '\t' with \u0009 but that still didn't work. I have also tried changing the tab span, but that also wasn't successful.
You need to set them all:
for (int i = 0; i < 1000; i += 100)
span.setSpan(new TabStopSpan.Standard(i), 0, span.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
I am trying to construct a SpannableString such that it looks like this:
Two characters (m, s) should be smaller than the rest.
I have tried to hold all the text in one SpannableString, and I also tried to concatenate two SpannableStrings via a SpannableStringBuilder.
The code for one Spannable looks like this:
spannable.setSpan(new RelativeSizeSpan(0.75f), spannable.length() - 1, spannable.length(), 0);
However, only one formatting is applied - when using the SpannableStringBuilder, only the "m" is smaller, and when using one SpannableString for the whole text, only the "s" is smaller.
Debugging also showed that Spannables seem to hold only one instance of RelativeSizeSpan, meaning there can be only one Span of one type. Is this true or expected behaviour?
Would it be advisable to concatenate TextViews instead?
EDIT: By the way, I am trying to remove a HTML.fromHtml() call here for performance reasons (many GC calls).
If you're still looking for an answer, I might have a solution. I had similar problems. I used TextUtils to concat the 2 SpannableString.
Here is some example code:
SpannableString span1 = new SpannableString("32m");
SpannableString span2 = new SpannableString("50s");
span1.setSpan(new RelativeSizeSpan(0.75f), 2, 3, 0);
span2.setSpan(new RelativeSizeSpan(0.75f), 2, 3, 0);
mTextView.setText(TextUtils.concat(span1," " ,span2));
You don't need 2 separate SpannableString.
A shorter solution can be :
SpannableString span1 = new SpannableString("32m50s");
span1.setSpan(new RelativeSizeSpan(0.75f), 2, 3, 0);
span1.setSpan(new RelativeSizeSpan(0.75f), 5, 6, 0);
mTextView.setText(span1);
You can use array of SpannableString.
Like in this case:
TextView lblDescription=(TextView ) findViewById(R.id.lblDescription);
SpannableString[] finalString = new SpannableString[stringSplit.length];
lblDescription.setText(TextUtils.concat(finalString));
I have using dynamic version of gbero's answer in my project,
public void updateTime(TextView tv) {
Calendar calendar = Calendar.getInstance();
SpannableString span = new SpannableString(
calendar.get(Calendar.HOUR_OF_DAY) + "h" + calendar.get(Calendar.MINUTE) + "m");
span.setSpan(new RelativeSizeSpan(0.75f), 2, 3, 0);
span.setSpan(new RelativeSizeSpan(0.75f), 5, 6, 0);
tv.setText(span);
}