Setting spannable string in android with combination of non-spannable strings - android

I have several strings uploaded to a String[]. These strings are set on a textview. However, I set the previous strings on my textview, as well. I need some of the strings to be red colored. I've heard of the SpannableString class which does exactly what I want, but the following call defeats my purpose of setting all the previous strings.
if(string from String[] contains ("R2")){//pseudo code
//build spanstring with all its properties
//combinedstrings = combinedstrings + spanstring;
}
else{
//string = string from String[]
//combinedstrings = combinedstrings + string;
}
textview.setText(spanstring, BufferType.SPANNABLE);
As you can see, this call only allows to set the spanstring not the combination of the spanstring including the non-spannable strings. I need the combination of both to be set at the same time.
I need a call that would set the text on the textview of both types of strings
the non-spannable and spannable ones.
thanks for any suggestions

Build the CharSequence you pass to setText with a SpannableStringBuilder. See https://developer.android.com/reference/android/text/SpannableStringBuilder.html This class allows you to append either string or spans and can be built into a single CharSequence.

Related

How can I change some of statements' text style in Firebase?

I'm trying to show some statements to users from Firebase. There are titles and contents in these statements. Trying to write titles with a boldly styled post. However, I cannot change the code from the android studio because I've assigned the whole description child to a single TextView. instead, I used expressions such as "\ n", which is also used in string expressions. Is it possible to write bold headlines? if so how?
For example ; here is my
Can I write "ilk olarak bulunduğunuz federal devletteki bir..." here by a bold style?
yes you can display, the approach i use is setting html from firebase
<p><b>This text is bold</b></p>
and in android side
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tvDesc.setText(Html.fromHtml(strfromfirebase, Html.FROM_HTML_MODE_COMPACT));
} else {
tvDesc.setText(Html.fromHtml(strfromfirebase));
}
You need to use a SpannableString in this case.
For example if I want to bold the word "Hello" in "Hello World", I would do something like:
String word = "Hello World";
SpannableString spannableString = new SpannableString(word);
spannableString.setSpan(new StyleSpan(Typeface.BOLD),0,5,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
0 is the starting index and 5 is the ending index

pass value to string.xml value that have a link inside it

I have this value in string.xml file:
<string name="rights">Copyright © All Rights Reserved %1$d <b> company name</b></string>
And I have applied this code that pass to the above text & set that text to the TextView
private void setupAppInfoRights() {
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
String rights = String.format(new Locale("en"), getString(R.string.rights), currentYear);
appInfoRights.setText(rights);
appInfoRights.setMovementMethod(LinkMovementMethod.getInstance());
}
When I remove the passed value everything goes fine & when the user click on the company name it takes him/her to the company website.
Please note that I have tried autoLink in xml when there is no value passed but it does not work as expected.
But, when I add the passed value & used the code above the company name has no underline & when the user clicks it , it will do nothing.
How to edit my above code to pass the current year & keep the link behavior normal?
Note: I have used String.format to display the current year as English number always despite the other locale numbers.
I think SpannableStringBuilder is what you are looking for.
TextView linkTv = (TextView) findViewById(R.id.link_tv);
linkTv.setMovementMethod(LinkMovementMethod.getInstance());
Spannable span = (Spannable) linkTv.getText();
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View widget){
//open the link
}
};
span.setSpan(clickableSpan, 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//for bold
span.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
If you want to make only certain part clickable then toggle the values of 0 and span.length() in setSpan().
When you have a string resource with both format arguments (like %1$d) and html markup, you have to use a multi-step process to create the styled CharSequence. This extra work is necessary because both Resources.getString(int, Object...) and String.format(String, Object...) can only return String instances, and not other CharSequence subclasses that are capable of holding styling information.
First, change your string resource to use html entities to escape the html tags:
<string name="rights">Copyright © All Rights Reserved %1$d <b> <a href="http://www.example.com/">company name</a></b></string>
Next, obtain a String with the format arguments replaced with the actual values you desire:
String withHtmlMarkup = getString(R.string.rights, currentYear);
Finally, use Html.fromHtml() to parse the html markup:
CharSequence styled = Html.fromHtml(withHtmlMarkup);
Then you can set this styled text to your TextView as normal:
appInfoRights.setText(styled);
appInfoRights.setMovementMethod(LinkMovementMethod.getInstance());
Developer guide: https://developer.android.com/guide/topics/resources/string-resource#FormattingAndStyling
Normally, this doesn't work because the format(String, Object...) and getString(int, Object...) methods strip all the style information from the string. The work-around to this is to write the HTML tags with escaped entities, which are then recovered with fromHtml(String), after the formatting takes place.

How could I interchange SpannableString to String without losing it's marked up properties?

If i have the following string:
String string = “My string”
Then i could change it’s color background using SpanString:
SpannableString spannableString = new SpannableString(string);
BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.RED);
spannableString.setSpan(backgroundSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Then if i make
Toast(context , spannableString , Toast.LENGHT_SHORT).show();
It will display a toast “My string” with changed background to red.
However , how can I show the same string without using the type SpannableString??
I mean Toast(context , [toString] spannableString , Toast.LENGHT_SHORT).show();
[toString]: my note
PS:I've tried
Toast.makeText(context, Html.fromHtml(spannableString.toString()), Toast.LENGTH_SHORT).show();
and
Toast.makeText(context, spannableString.toString(), Toast.LENGTH_SHORT).show();
because i need to attribute this to a kind of:
entity.setAttribute([toString]Spannable);
but not showing commom text.
There is no way without using Spannables. Spannables are how you add formatting data to text in Android. Even your fromHTML hack turns html into a spannable.
The correct thing to do is probably take whatever API you're using that requires a string and make it take a CharSequence instead.

How do I prepend a String to an Android TextView?

There's TextView.append(), but that adds the text to the end of the TextView. I want what I append to go in the beginning (ie, show up on the top of the TextView box).
Have you tried this
textview.setText(" append string" + textView.getText());
Though the spannables will get lost by this method.
If you're concerned about spannables, you can use something like this:
textView.getEditableText().insert(0, "string to prepend");
The getEditableText() returned null to me. Instead, to prepend text to a spannable, I set the text buffertype to SPANNABLE:
in code:
myTextView.setText(myText, TextView.BufferType.SPANNABLE);
or using xml property android:bufferType on your TextView.
Then cast the getText() to Spannable, after which I concat the extra text with existing text:
Spannable currentText = (Spannable) tvTitle.getText();
CharSequence indexedText = TextUtils.concat(String.format("%d. ", index), currentText);
myTextView.setText(indexedText);
As far as I can tell all functions are available from API level 1.
Then use the string you want to append say "hello" to the textview as
textview.setText("hello"+textView.getText())

Specifying "strikethrough" on a section of TextView text

I have a block of text coming from a webservice, and depending on some tags which I have predefined, I want to style the text before setting it to my TextView. For bold, italics, and underline, I was able to do this easily with the replaceAll command:
PageText = PageText.replaceAll("\\*([a-zA-Z0-9]+)\\*", "<b>$1</b>");
PageText = PageText.replaceAll("=([a-zA-Z0-9]+)=", "<i>$1</i>");
PageText = PageText.replaceAll("_([a-zA-Z0-9]+)_", "<u>$1</u>");
txtPage.setText(Html.fromHtml(PageText), TextView.BufferType.SPANNABLE);
So, to bold a word, surround it with *'s, for italics, surround with _.
But, for strikethrough, Html.fromHtml does not support the "strike" tag, so it can't be done this same way. I've seen examples of using Spannable to set the styling on one section of text, but it requires positional numbers. So, I guess I could loop through the text, searching for - (the tag to represent the strike), then searching for the next one, spanning the text in between, and repeating for all such strings. It will end up being 10 lines of looping code as opposed to 1 for the others, so I'm wondering if there is a more elegant solution out there.
If it is just TextView you can strike through using paint flags
TextView tv=(TextView) v.findViewById(android.R.id.text1);
tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
#Suresh solution works if you want to strikethrough the entire TextView but if you want to strikethrough only some portions of the text then use the code below.
tvMRP.setText(text, TextView.BufferType.SPANNABLE);
Spannable spannable = (Spannable) tvMRP.getText();
spannable.setSpan(new StrikethroughSpan(), 3, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Here text is the text which we want out TextView to display, 3 is the no. of characters (starting from 0) from where the strikethrough will start.
You can do it with a custom TagHandler such as the one on this SO question:
Spanned parsed = Html.fromHtml(PageText, null, new MyHtmlTagHandler());
And the TagHandler implements the methods:
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if(tag.equalsIgnoreCase("strike") || tag.equals("s")) {
processStrike(opening, output);
}
}
....
Are you sure Html.fromHtml doesn't support <strike>? It's listed in this Commonsware blog post
It looks like is not really supported, at least it does not work on Android 3.1.
#RMS2 if text is small you can split it into two or three separate text views and apply flag only to the one which you want, not perfect for long texts ;(
Most of the applications we work in are going to use text somewhere throughout the project and thankfully, KTX provides some extension functions when it comes to these parts. For text, we essentially have some functions available for the SpannableStringBuilder class.
For example, after instantiating a Builder instance we can use the build methods to append some bold text:
textView.text =buildSpannedString {
strikeThrough {
append(
value ?: ""
)
}
}

Categories

Resources