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
Related
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:
I was trying to remove style from my SpannableString but unfortunately is not working, my aim is to remove the style when I click on the text.
SpannableString content = new SpannableString("Test Text");
content.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, content.length(), 0);
...
onClick Action :
content.removeSpan(new StyleSpan(Typeface.BOLD_ITALIC)) // not working
Two styleSpan you new is not the same object. You can use a non-anonymous object to point it. Change your code like that:
StyleSpan styleSpan = new StyleSpan(Typeface.BOLD_ITALIC);
content.setSpan(styleSpan , 0, content.length(), 0);
onClick Action:
content.removeSpan(styleSpan);
textView.setText(content);// to redraw the TextView
As Zheng Xingjie pointed out you can remove a particular span with removeSpan() but you need to store the span object.
However, I came across a case that I need to remove a group of the same style spans anonymously, and leave other styles, So I did it by iterating on this particular type of spans as follows:
In my case, it was BackgroundColorSpan, but I will use StyleSpan like it had been asked:
Java
SpannableString content = new SpannableString("Test Text");
content.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, content.length(), 0);
StyleSpan[] spans = content.getSpans(0, content.length(), StyleSpan.class);
for (StyleSpan styleSpan: spans) content.removeSpan(styleSpan);
textview.setText(content);
Kotlin
val content = SpannableString("Test Text")
content.setSpan(StyleSpan(Typeface.BOLD_ITALIC), 0, content.length, 0)
val spans = content.getSpans(0, content.length, StyleSpan::class.java)
for (styleSpan in spans) content.removeSpan(styleSpan)
textview.setText(content)
I used the below code to add image span.
Drawable happySmiley = ctx.getResources().getDrawable(
R.drawable.img_smile);
happySmiley.setBounds(0, 0, happySmiley.getIntrinsicWidth(),
happySmiley.getIntrinsicHeight());
Drawable sadSmiley = ctx.getResources()
.getDrawable(R.drawable.ic_launcher);
sadSmiley
.setBounds(0, 0, sadSmiley.getIntrinsicWidth(),
sadSmiley.getIntrinsicHeight());
SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append("Some text ");
builder.setSpan(new ImageSpan(happySmiley), builder.length()-1, builder.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.append(". More text [sad_smiley_anchor]");
builder.setSpan(new ImageSpan(sadSmiley), builder.length()
- "[sad_smiley_anchor]".length(), builder.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tvSS.setText(builder);
o/p Some text (smiley). More text (smiley).
But I want to display the smiley above the "Some" in "Some text". Like
(Smiley) (Smiley)
Some Text. More text.
If smiley can be set as background to "Some" in "Some text" like setForegroundSpan() etc. then also problem can be short out. Please comment on this.
Thanks
I'm pretty new to android, Java and sqlite. For my first program I'm creating a program that will take user input and place in predefined text.
Example: "text" string1 "more text" string2 "even more text" etc
My text will be one color and strings will display in another color.
I'm using sqlite to seperate my data and code and this is where I hit a wall. Trying to find help on how I will be able to combine my above text into one row/column in my database table.
Using only one above example i could get this up and running. But there will be 50+ of above example for release making a database a must especially when I want to add more after release.
Most probably you've read up on SpannableStringBuilder, which allows you to add color to the text in your TextView's content. Check out the code below:
SpannableStringBuilder ssb = new SpannableStringBuilder(<your text>);
ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(255, 0, 0));
ssb.setSpan(fcs, 0, ssb.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(ssb);
The code above will work in most cases, however what you want is to have different alternating colors on a single TextView. Then you should do the following:
String text = your_text + text_from_database;
SpannableStringBuilder ssb = new SpannableStringBuilder(text);
ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(255, 0, 0));
ForegroundColorSpan fcs2 = new ForegroundColorSpan(Color.rgb(0, 255 0));
ssb.setSpan(fcs, 0, your_text, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.setSpan(fcs2, your_text.length(), ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(ssb);
The above code will now work, but you'll notice that if you add another text your_another_text and want to use the previous fcs instance for a second time, the previously colored your_text will now lose its formatting (color). This time you'll need to create another ForegroundColorSpan fcs3 to format the third part of the SpannableStringBuilder. The key here is to use a character style in a setSpan method only once. See below:
String testTest = "abcdefgh";
String testTest2 = "ijklmnop";
String testTest3 = "qrstuvwxyz";
SpannableStringBuilder ssb = new SpannableStringBuilder(testTest+testTest2+testTest3);
ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(255, 0, 0));
ForegroundColorSpan fcs2 = new ForegroundColorSpan(Color.rgb(0, 255, 0));
ForegroundColorSpan fcs3 = new ForegroundColorSpan(Color.rgb(255, 0, 0));
ssb.setSpan(fcs, 0, testTest.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
ssb.setSpan(fcs2, testTest.length(), (testTest+testTest2).length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
ssb.setSpan(fcs3, (testTest+testTest2).length(), ssb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
test.setText(ssb);
This method is good if you know you have a fixed number of String elements in your SpannableStringBuilder. If you have wish to have a TextView of dynamic length and number of elements, you need to do this in a different approach. What worked for me was to convert each string element into a SpannableString, use setSpan, and append it to the TextView. This is useful if you're using a loop to build your TextView.
TextView test = (TextView)findViewById(R.id.test);
String testTest = "abcdefgh";
String testTest2 = "ijklmnop";
String testTest3 = "qrstuvwxyz";
SpannableString ssb = new SpannableString(testTest);
ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(255, 0, 0));
ForegroundColorSpan fcs2 = new ForegroundColorSpan(Color.rgb(0, 255, 0));
ForegroundColorSpan fcs3 = new ForegroundColorSpan(Color.rgb(255, 0, 0));
ssb.setSpan(fcs, 0, ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
test.setText(ssb);
SpannableString ssb2 = new SpannableString(testTest2);
ssb2.setSpan(fcs2, 0, ssb2.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
test.append(ssb2);
SpannableString ssb3 = new SpannableString(testTest3);
ssb3.setSpan(fcs3, 0, ssb3.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
test.append(ssb3);
After I have a small list in a listview how do I go through and change the color of any text matching a string? They will always be the same textview. Do I have to do anything custom to do this or just loop through the listview?
use this to have different color
TextView tv = new TextView(xx);
SpannableStringBuilder text = new SpannableStringBuilder("your string");
text.setspan(new ForegroundColorSpan(Color.RED),
startIndex, len,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setspan(new ForegrounColorSpan(Color.GREEN),
startIndex,endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(text);
and use fromHTML(String ) method for Styles
if you want to get the index of a specified string use indexOf("your string")
If you are making a custom list View than you have to inflate it and after that you can setTextColor(Color.parse("#ffffff"));
or you can take reference from this
http://developer.android.com/resources/tutorials/views/hello-listview.html
Thanks