I using linkify to highlight URL and Emails in my text view, it work correctly in first render but when i try to change text not work.
in my text view i use spannable to append see more and see less when text length more than specific number of string.
the following my span function that append text
private static SpannableStringBuilder getTextToShown(Activity activity, String text, boolean showMore) {
SpannableStringBuilder sb;
final ForegroundColorSpan fcs = new ForegroundColorSpan(activity.getResources().getColor(R.color.cyan_mostly_black_light));
String textToShow;
if (!showMore) {
textToShow = text + " " + activity.getResources().getString(R.string.see_less);
sb = new SpannableStringBuilder(textToShow);
sb.setSpan(fcs, text.length(), textToShow.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), text.length(), textToShow.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
textToShow = text.substring(0, NUMBER_OF_CHAR_TO_SHOWN - 1) + " " + activity.getResources().getString(R.string.see_more);
sb = new SpannableStringBuilder(textToShow);
sb.setSpan(fcs, NUMBER_OF_CHAR_TO_SHOWN, textToShow.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), NUMBER_OF_CHAR_TO_SHOWN, textToShow.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return sb;
}
and i use it by the following
if (postModel.getObject().getContent().length() > 140) {
post_data.setText(getTextToShown(activity, postModel.getObject().getContent(), true));
showMore = true;
post_data.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (showMore) {
post_data.setText(getTextToShown(activity, postModel.getObject().getContent(), false));
showMore = false;
} else {
post_data.setText(getTextToShown(activity, postModel.getObject().getContent(), true));
showMore = true;
}
}
});
} else {
post_data.setText(postModel.getObject().getContent());
}
and I add linkify by add this
post_data.setMovementMethod(LinkMovementMethod.getInstance());
post_data.setLinkTextColor(Color.BLUE);
Linkify.addLinks(post_data, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS);
till now it's work fine without any problem but when try to click in see more in textview it render the new text in textview but not highlight links or emails, I try to run it in UI thread but also i get the same result. Any help ?
I solve it by remove linkify and add only the following in xml
android:textColorLink="#color/blue.pure"
android:autoLink="all"
and use.
Related
I want to set color just on "read more" string :
holder.Title.setText(current.getTitle());
holder.Description.setText(start+"...."+"read more");
holder.Date.setText(current.getPubDate());
I have tried to use html.fromhtml but it is not working with me !!!
Try as follow
String textFirstPart = start + "....";
String textSecondPart = "read more";
String text = textFirstPart + textSecondPart;
Spannable spannable = new SpannableString(text);
spannable.setSpan(new ForegroundColorSpan(Color.RED), textFirstPart.length(),
(textFirstPart + textSecondPart).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.Description.setText(spannable, TextView.BufferType.SPANNABLE);
Here you go
SpannableString styledString = new SpannableString("read more");
// change text color
styledString.setSpan(new ForegroundColorSpan(Color.BLUE), 0, 8, 0);
// underline text
styledString.setSpan(new UnderlineSpan(), 0, 8, 0);
Read more here
Starting from Android N,
the method Html.fromHtml(htmlText) is deprecated and you have to use
Html.fromHtml(htmlText, MODE) instead, so use the following condition,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
holder.setText(Html.fromHtml(sourceString,Html.FROM_HTML_MODE_LEGACY);
} else {
holder.setText(Html.fromHtml(sourceString);
}
Reference:
https://developer.android.com/reference/android/text/Html#FROM_HTML_MODE_COMPACT
I want to show a text in a TextView with different colors and put control characters to break lines \n and tabs \t\t...
I do this...
SpannableStringBuilder sb = new SpannableStringBuilder("");
ForegroundColorSpan fcs_red = new ForegroundColorSpan(Color.RED);
ForegroundColorSpan fcs_blu = new ForegroundColorSpan(Color.BLUE);
...
for(int j = 0; j < columns.length; j++)
{
if(columns[j].equals("<")) continue;
if(columns[j].contains("/") && columns[j].contains(":"))
{
columns[j] = columns[j].replace("<TD>", "\n");
sb_aux = new SpannableStringBuilder(columns[j]);
sb_aux.setSpan(fcs_red, 0, sb_aux.length(),Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
else
{
if(columns[j].contains("<TD>"))
{
columns[j] = columns[j].replace("<TD>", "\n\t\t");
sb_aux = new SpannableStringBuilder(columns[j]);
sb_aux.setSpan(fcs_blu, 0, sb_aux.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
else
{
columns[j] = "\n\t\t"+columns[j];
sb_aux = new SpannableStringBuilder(columns[j]);
sb_aux.setSpan(fcs_blu, 0, sb_aux.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
}
sb.append(sb_aux);
}
myTextView.setText(sb);
So, the first part of text is showed in RED as expected, but the rest of text do not alternate in RED or BLUE as expected and the \n and \t was not recognized
My intention was spanning text in pieces and appending to a SpannableStringBuilder to be showed in TextView, any clues ?
Using the following code you can show rich text in a TextView.
String html = "<font color='red'>This is red</font>" +
"<br/>new line \t some indent <b>BOLD</b>";
myTextView.setText(Html.fromHtml(html));
I have a textview as like the following:
txtByRegistering.setText("By Registering you agree to terms and condition and privacy policy");
It is just a big text. So, I used marquee to scroll the text horizontally. that works fine. My Question is, How to invoke the click event while clicking the selected scrolling text .
Say for ex :
when user click the word "Registering" in the above textview, I have to invoke the new Intent.
When the user click on the word "Terms" , I have to
invoke another new Intent (An Activity with webview as Terms has URL Link).
As the word "Registering" and "Terms" are Web URLs, I tried something like below :
String mRegDesc = "By registering you agree to the " + "<a href=\""
+ Constant.URL + "/terms_and_conditions"
+ "\">Terms of Use</a> " + "and " + "<a href=\"" + Constant.URL
+ "/privacy" + "\">Privacy Policy</a> ";
txtByRegistering.setText(Html.fromHtml(mRegDesc));
txtByRegistering.setMovementMethod(LinkMovementMethod.getInstance());
txtByRegistering.setSelected(true);
txtByRegistering.setTypeface(mTyFaceOverLockReg, Typeface.BOLD);
The above code works fine and it brings me to the browser when i click the word "Terms" But i wish to go to new Activity.
Finally,
I found the solution for that,
Here is the solution :
SpannableString SpanString = new SpannableString(
"By Registering you agree to the Terms of Use and Privacy Policy");
ClickableSpan teremsAndCondition = new ClickableSpan() {
#Override
public void onClick(View textView) {
Intent mIntent = new Intent(SignUp.this, CommonWebView.class);
mIntent.putExtra("isTermsAndCondition", true);
startActivity(mIntent);
}
};
// Character starting from 32 - 45 is Terms and condition.
// Character starting from 49 - 63 is privacy policy.
ClickableSpan privacy = new ClickableSpan() {
#Override
public void onClick(View textView) {
Intent mIntent = new Intent(SignUp.this, CommonWebView.class);
mIntent.putExtra("isPrivacyPolicy", true);
startActivity(mIntent);
}
};
SpanString.setSpan(teremsAndCondition, 32, 45, 0);
SpanString.setSpan(privacy, 49, 63, 0);
SpanString.setSpan(new ForegroundColorSpan(Color.BLUE), 32, 45, 0);
SpanString.setSpan(new ForegroundColorSpan(Color.BLUE), 49, 63, 0);
SpanString.setSpan(new UnderlineSpan(), 32, 45, 0);
SpanString.setSpan(new UnderlineSpan(), 49, 63, 0);
txtByRegistering.setMovementMethod(LinkMovementMethod.getInstance());
txtByRegistering.setText(SpanString, BufferType.SPANNABLE);
txtByRegistering.setSelected(true);
thanks to Shayan pourvatan.
Let assume here is your complete string
By Signing up, I agree to Terms of Conditions & Privacy Policy
and string you want to make clickable is
Terms of Conditions and Privacy Policy
so, here is my trick.....
ClickableSpan terms = new ClickableSpan() {
#Override
public void onClick(View widget) {
new Utils(getActivity()).shortToast("Terms");
}
};
ClickableSpan privacy = new ClickableSpan() {
#Override
public void onClick(View widget) {
new Utils(getActivity()).shortToast("Privacy");
}
};
the main function for this
public void setClickableString(String wholeValue, TextView textView, final String[] clickableValue, ClickableSpan[] clickableSpans) {
SpannableString spannableString = new SpannableString(wholeValue);
for (int i = 0; i < clickableValue.length; i++) {
ClickableSpan clickableSpan = clickableSpans[i];
String link = clickableValue[i];
int startIndexOfLink = wholeValue.indexOf(link);
spannableString.setSpan(clickableSpan, startIndexOfLink, startIndexOfLink + link.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
textView.setHighlightColor(
Color.TRANSPARENT); // prevent TextView change background when highlight
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(spannableString, TextView.BufferType.SPANNABLE);
}
and here is the function calling
setClickableString(getString(R.string.terms_and_policy), tv_terms, new String[]{"Terms of Conditions", "Privacy Policy"}, new ClickableSpan[]{terms, privacy});
Use this one it works for me two click in single TextView
Step1-: Your text will be in SpannableString
SpannableString ss = new SpannableString("By Registering you agree to terms and condition and privacy policy");
Step2:-add click in ClickableSpan like this
ClickableSpan Registering = new ClickableSpan() {
#Override
public void onClick(View textView) {
Intent intent=new Intent(this,WebView_Activity.class);
startActivity(intent);
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(true);
}
};
ClickableSpan terms = new ClickableSpan() {
#Override
public void onClick(View textView) {
Intent intent=new Intent(this,WebView_Activity.class);
startActivity(intent);
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(true);
}
};
Final step add your click on SpannableString with character starting and ending index like Registering word in start at 3rd position and end at 11 so add click for Registering word
ss.setSpan(Registering , 3, 11, 0);
same for term after this add your SpannableString on your TextView
textview.setMovementMethod(LinkMovementMethod.getInstance());
textview.setText(ss, TextView.BufferType.SPANNABLE);
textview.setSelected(true);
I would suggest below code for clickable string in TextView it is dynamic.
Advantage of this code is if you have same String multiple times you can have click on both Strings. For example if you want to set click and String is Boy is playing cricket. Boy is playing football. Boy is two times both word will be clickable.
public void setClicksOnString(String completeString, List<String> stringsToClick, TextView textView) {
SpannableString spannableString = new SpannableString(completeString);
for (int m = 0; m < stringsToClick.size(); m++) {
Matcher matcher = Pattern.compile(stringsToClick.get(m)).matcher(spannableString);
while (matcher.find()) {
ClickableSpan stringClick = new ClickableSpan() {
#Override
public void onClick(View widget) {
//you compare the string and your click logics
}
};
spannableString.setSpan(stringClick, matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
textView.setHighlightColor(
Color.TRANSPARENT); // prevent TextView change background when highlight
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(spannableString, TextView.BufferType.SPANNABLE);
}
In addition, if you want to know in which text the user clicked dynamically, use below
ClickableSpan listener = new ClickableSpan() {
#Override
public void onClick(View textView) {
TextView tv = (TextView) textView;
Spanned s = (Spanned) tv.getText();
int start = s.getSpanStart(this);
int end = s.getSpanEnd(this);
String clickedText = s.toString().substring(start,end);
}
};
I need to change the color of the String which appears randomly in a sentence.
Ex: These following sentences are what I need to display.
hai #xyz how are you.
i am learning #abc android.
In this I have to change the color of the words "#xyz", "#abc" i.e, which starts with the character "#".
I used some string functions split(), subString(). but I am not getting what i need.
so, please guide me how to solve this.
Use SpannableString for ex:
SpannableString ss = new SpannableString("hai #xyz how are you.");
ss.setSpan(new ForegroundColorSpan(Color.RED), 4, 9, 0);
Try following to change color of each word with #:
String s="hai #xyz how are you.";
ForegroundColorSpan span = new ForegroundColorSpan(Color.RED);
SpannableString ss = new SpannableString(s);
String[] ss = s.split(" ");
int currIndex = 0;
for (String word : ss) {
if (word.startsWith("#")) {
ss.setSpan(span, currIndex,currIndex+ word.length(), 0);
}
currIndex += (word.length() + 1);
}
you can use this code:
t.setText(first + next, BufferType.SPANNABLE);
Spannable s = (Spannable)t.getText();
int start = first.length();
int end = start + next.length();
s.setSpan(new ForegroundColorSpan(0xFFFF0000), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
or you can use html:
String first = "This word is ";
String next = "<font color='#EE0000'>red</font>";
t.setText(Html.fromHtml(first + next));
You can easily achieve this using html tags
tv_message.setText(Html.fromHtml("<font color=\"#000000\">"+"Hi "+"</font>"+" "+"<font color=\"#EE0000\">"+"XYZ "+"</font>"+" "+"<font color=\"#000000\">"+"How are You ? " + "</font>"));
I am looking for a way to change the color of a text of a single word in a TextView from within an Activity.
For example, with this:
String first = "This word is ";
String next = "red"
TextView t = (TextView) findViewById(R.id.textbox);
t.setText(first + next);
How would I change the color of the next text to red?
Easiest way I know is to just use html.
String first = "This word is ";
String next = "<font color='#EE0000'>red</font>";
t.setText(Html.fromHtml(first + next));
But this will require you to rebuild the TextView when (if?) you want to change the color, which could cause a hassle.
t.setText(first + next, BufferType.SPANNABLE);
Spannable s = (Spannable)t.getText();
int start = first.length();
int end = start + next.length();
s.setSpan(new ForegroundColorSpan(0xFFFF0000), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
you have to use spannable this will also allows you to increase some text's size, make it bold etc.... even put in some image.
Use SpannableStringBuilder like this :
SpannableStringBuilder builder = new SpannableStringBuilder();
SpannableString str1= new SpannableString("Text1");
str1.setSpan(new ForegroundColorSpan(Color.RED), 0, str1.length(), 0);
builder.append(str1);
SpannableString str2= new SpannableString(appMode.toString());
str2.setSpan(new ForegroundColorSpan(Color.GREEN), 0, str2.length(), 0);
builder.append(str2);
TextView tv = (TextView) view.findViewById(android.R.id.text1);
tv.setText( builder, TextView.BufferType.SPANNABLE);
for long string you can use this:
String help = getString(R.string.help);
help = help.replace("some word", "<font color='#EE0000'>some word</font>");
txtDesc.setText(Html.fromHtml(help));
If you want to change the state of all the instances of a specific String inside a TextView text(case insensitive) you can use StringBuilders and SpannableString like this:
StringBuilder textBuilder = new StringBuilder(myTextView.getText().toString());
StringBuilder searchedTextBuilder = new StringBuilder((mySearchedString));
SpannableString spannableString = new SpannableString(myTextView.getText().toString());
int counter = 0;
int index = 0;
for (int i = 0;i < textBuilder.length() - mySearchedString.length() - 1;i++)
{
counter = 0;
if (Character.toLowerCase(textBuilder.charAt(i)) == Character.toLowerCase(searchedTextBuilder.charAt(index)))
{
counter++;
index++;
for (int j = 1,z = i + 1;j < mySearchedString.length() - 1;j++,z++)
{
if (Character.toLowerCase(textBuilder .charAt(z)) == Character.toLowerCase(searchedTextBuilder .charAt(index)))
{
counter++;
index++;
}
else
{
index++;
if (index % mySearchedString.length() == 0)
{
index = 0;
}
break;
}
}
if (counter == mySearchedString.length() - 1) // A match
{
spannableString.setSpan(new ForegroundColorSpan(Color.RED), i,
i + mySearchedString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // Do the change you want(In this case changing the fore ground color to red)
index = 0;
continue;
}
else
{
index = 0;
continue;
}
}
}
myTextView.setText(spannableString);
}
Store the whole TextView text inside a StringBuilder.
Store the searched string inside a StringBuilder.
Store the wholre TextView text inside a SpannableString
Make a simple operation to find all the String instances inside the TextView text and change them when reached.
Set the text value of the TextView to the SpannableString.
I implemented a utility function in Kotlin for my own usecase and maybe useful for someone else.
fun getCusomTextWithSpecificTextWithDiffColor(textToBold: String, fullText: String,
targetColor: Int) =
SpannableStringBuilder(fullText).apply {
setSpan(ForegroundColorSpan(targetColor),
fullText.indexOf(textToBold),
(fullText.indexOf(textToBold) + textToBold.length),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
How I am using it:
context?.let {
infoMessage.text = AppUtils.getCusomTextWithSpecificTextWithDiffColor(
wordAsBold,
completeSentence, ContextCompat.getColor(it, R.color.white))
}
USE:
makeTextBold("Your order is accepted","accepted", textView);
makeTextBold("Your order is canceled","canceled", textView);
Function:
public static void makeTextBold(String sentence, String word, AppCompatTextView textView) {
SpannableStringBuilder builder = new SpannableStringBuilder();
int startIndex = sentence.indexOf(word.toLowerCase().trim());
int endIndex = startIndex + word.toLowerCase().trim().length();
SpannableString spannableString = new SpannableString(sentence);
StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
spannableString.setSpan(boldSpan, startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //To make text Bold
spannableString.setSpan(new ForegroundColorSpan(Color.RED), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //To change color of text
builder.append(spannableString);
textView.setText(builder, TextView.BufferType.SPANNABLE);
}
I think this is more readable
for coloring a word in a string
it is also probably more efficient a bit because you write once
String str = YOUR_STRING
Spannable s = new SpannableString(str);
int start = str.indexOf(err_word_origin);
int end = start + err_word_origin.length();
s.setSpan(new ForegroundColorSpan(Color.BLUE), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
YOUR_TEXT_VIEW.setText(s , TextView.BufferType.SPANNABLE);
my solution extension:
fun coloredText(
baseText: String,
coloredText: String,
targetColor: Int
): SpannableStringBuilder {
val transformText = "$baseText $coloredText"
return SpannableStringBuilder(transformText).apply {
setSpan(
ForegroundColorSpan(targetColor),
transformText.indexOf(coloredText),
(transformText.indexOf(coloredText) + coloredText.length),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
Usage
binding.mytextView.title = coloredText(
baseText = getString(R.string.my_title),
coloredText = getString(R.string.my_title_colored_part),
targetColor = ContextCompat.getColor(requireContext(), R.color.blue))
Iv'e found this best answer
https://stackoverflow.com/a/53573169/14250778
just changed one line to support also words that starts with uppercase letter
public void setHighLightedText(TextView tv, String textToHighlight) {
// added "toLowerCase()" to support words that starts with uppercase letter
String tvt = tv.getText().toString().toLowerCase();
int ofe = tvt.indexOf(textToHighlight, 0);
Spannable wordToSpan = new SpannableString(tv.getText());
for (int ofs = 0; ofs < tvt.length() && ofe != -1; ofs = ofe + 1) {
ofe = tvt.indexOf(textToHighlight, ofs);
if (ofe == -1)
break;
else {
// set color here
wordToSpan.setSpan(new BackgroundColorSpan(0xFFFFFF00), ofe, ofe + textToHighlight.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(wordToSpan, TextView.BufferType.SPANNABLE);
}
}
}