text = text + CepVizyon.getPhoneCode() + "\n\n"
+ getText(R.string.currentversion) + CepVizyon.getLicenseText();
activationText.setText(text);
myTextView.setText(text);
I want to change color for CepVizyon.getPhoneCode()'s string. How can I do this?
Spannable is more flexible:
String text2 = text + CepVizyon.getPhoneCode() + "\n\n"
+ getText(R.string.currentversion) + CepVizyon.getLicenseText();
Spannable spannable = new SpannableString(text2);
spannable.setSpan(new ForegroundColorSpan(Color.WHITE), text.length(), (text + CepVizyon.getPhoneCode()).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
myTextView.setText(spannable, TextView.BufferType.SPANNABLE);
If you have static text that needs color, you can add it without any code via the strings file:
<string name="already_have_an_account">Already have an account? <font color='#01C6DB'>Login</font></string>
then
<TextView
android:layout_width="wrap_content"
android:layout_height="64dp"
android:text="#string/already_have_an_account"/>
result
I'm not sure which API versions this works on, but it doesn't work for API 19 that I've tested so far, so probably only some of the most recent API versions support this.
As #hairraisin mentioned in the comments, try using fgcolor instead of color for the font color, then it should work for lower API levels, but need more testing to be sure.
myTextView.setText(Html.fromHtml(text + "<font color=white>" + CepVizyon.getPhoneCode() + "</font><br><br>"
+ getText(R.string.currentversion) + CepVizyon.getLicenseText()));
Here solution in Kotlin that uses SpannableString to change color of part of a string.
val phoneCodeColor = ContextCompat.getColor(this, R.color.myColor)
val text = SpannableStringBuilder()
.color(phoneCodeColor) { append("${ CepVizyon.getPhoneCode() }") }
.append("\n\n")
.append(getString(R.string.currentversion))
.append(${ CepVizyon.getLicenseText() })
activationText.text = text
myTextView.text = text
With regards to Maneesh's answer, this will work but you need to add and escape the quotes for the color attribute.
myTextView.setText(Html.fromHtml(text + "<font color=\"#FFFFFF\">" + CepVizyon.getPhoneCode() + "</font><br><br>"
+ getText(R.string.currentversion) + CepVizyon.getLicenseText()));
It is good for me!
Spannable spannable = new SpannableString("ABC In-Network DEF");
String str = spannable.toString();
iStart = str.indexOf("In-Network");
iEnd = iStart + 10;/*10 characters = in-network. */
SpannableString ssText = new SpannableString(spannable);
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View widget) {
//your code at here.
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(true);
ds.setColor(getResources().getColor(R.color.green));
}
};
ssText.setSpan(clickableSpan, iStart, iEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mTextView.setText(ssText);
mTextView.setMovementMethod(LinkMovementMethod.getInstance());
mTextView.setHighlightColor(Color.TRANSPARENT);
mTextView.setEnabled(true);
Here's a colorize function based on andyboot's answer:
/**
* Colorize a specific substring in a string for TextView. Use it like this: <pre>
* textView.setText(
* Strings.colorized("The some words are black some are the default.","black", Color.BLACK),
* TextView.BufferType.SPANNABLE
* );
* </pre>
* #param text Text that contains a substring to colorize
* #param word The substring to colorize
* #param argb The color
* #return the Spannable for TextView's consumption
*/
public static Spannable colorized(final String text, final String word, final int argb) {
final Spannable spannable = new SpannableString(text);
int substringStart=0;
int start;
while((start=text.indexOf(word,substringStart))>=0){
spannable.setSpan(
new ForegroundColorSpan(argb),start,start+word.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
substringStart = start+word.length();
}
return spannable;
}
I have made this little function, just pass in your text to color, the start and end indexes of what you want to color of that text and the color itself
Kotlin
private fun colorMyText(inputText:String,startIndex:Int,endIndex:Int,textColor:Int):Spannable{
val outPutColoredText: Spannable = SpannableString(inputText)
outPutColoredText.setSpan(
ForegroundColorSpan(textColor), startIndex, endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
return outPutColoredText
}
Usage
txt_comment.text = colorMyText("Comentario: ${item.comentario}",0,13,Color.BLACK)
Use character escapes + Html.fromHtml()
How to store the String in the string resource folder
<string name="textFromRes">
<font color="#FF0000">This is colored in red </font> This is not
</string>
How to show in TextView?
String text = this.getResources().getString(R.string.textFromRes);
htmlText.setText(Html.fromHtml(text));
Bonus:
The String in the output looks like this
<string name="textFromRes">
<font color="#FF0000">This is colored in red </font> This is not
<br />
<h1> This is h1 heading </h1>
<br />
<h3> This is h2 subheading</h3>
<br />
<b> This text is bold</b>
<br />
<i> This text is italic</i>
<br />
Android users expect your app to look and behave in a way that is
consistent with the platform. Not only should you follow material
design guidelines for visual and navigation patterns,
but you should also follow quality guidelines for compatibility,
performance, security, and more.
<br />
<br />
The following links provide everything you need to design a high quality Android app.
</string>
With a general-purpose Kotlin extension function, it would look like this:
/**
* Change the color of a part of the text contained in this textView
*
* #param subStringToColorize has to already be set in the textView's text
* #param colorResId
*/
fun TextView.colorize(subStringToColorize: String, #ColorRes colorResId: Int) {
val spannable: Spannable = SpannableString(text)
val startIndex = text.indexOf(subStringToColorize, startIndex = 0, ignoreCase = false)
val endIndex = startIndex + subStringToColorize.length
val color: Int = ContextCompat.getColor(context, colorResId)
if (startIndex != -1) {
spannable.setSpan(ForegroundColorSpan(color),
startIndex,
endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
setText(spannable, TextView.BufferType.SPANNABLE)
}
}
I didn't like the idea of doing this by code every time i want to color parts of the text which i have been doing a lot in all of my apps (and since in some case text is being set in runtime with different inline-defined colors) so i created my own MarkableTextView.
The idea was to:
Detect XML tags from string
Identify and match tag name
Extract and save attributes and position of text
Remove tag and keep content
Iterate through attributes and apply styles
Here's the process step by step:
First i needed a way to find XML tags in a given string and Regex did the trick..
<([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)(?:\s+([^>]*))?>([^>][^<]*)</\1\s*>
For the above to match an XML tag it has to have the following criteria:
Valid tag name like <a> <a > <a-a> <a ..attrs..> but not < a> <1>
Closing tag that has a matching name like <a></a> but not <a></b>
Any content, since there's no need to style "nothing"
Now for the attributes we're going to use this one..
([a-zA-Z]+)\s*=\s*(['"])\s*([^'"]+?)\s*\2
It has the same concept and generally i didn't need to go far for both since the compiler will take care of the rest if anything goes out of format.
Now we need a class that can hold the extracted data:
public class MarkableSheet {
private String attributes;
private String content;
private int outset;
private int ending;
private int offset;
private int contentLength;
public MarkableSheet(String attributes, String content, int outset, int ending, int offset, int contentLength) {
this.attributes = attributes;
this.content = content;
this.outset = outset;
this.ending = ending;
this.offset = offset;
this.contentLength = contentLength;
}
public String getAttributes() {
return attributes;
}
public String getContent() {
return content;
}
public int getOutset() {
return outset;
}
public int getContentLength() {
return contentLength;
}
public int getEnding() {
return ending;
}
public int getOffset() {
return offset;
}
}
Before anything else, we're going to add this cool iterator that i've been using for long to loop through matches (can't remember the author):
public static Iterable<MatchResult> matches(final Pattern p, final CharSequence input) {
return new Iterable<MatchResult>() {
public Iterator<MatchResult> iterator() {
return new Iterator<MatchResult>() {
// Use a matcher internally.
final Matcher matcher = p.matcher(input);
// Keep a match around that supports any interleaving of hasNext/next calls.
MatchResult pending;
public boolean hasNext() {
// Lazily fill pending, and avoid calling find() multiple times if the
// clients call hasNext() repeatedly before sampling via next().
if (pending == null && matcher.find()) {
pending = matcher.toMatchResult();
}
return pending != null;
}
public MatchResult next() {
// Fill pending if necessary (as when clients call next() without
// checking hasNext()), throw if not possible.
if (!hasNext()) { throw new NoSuchElementException(); }
// Consume pending so next call to hasNext() does a find().
MatchResult next = pending;
pending = null;
return next;
}
/** Required to satisfy the interface, but unsupported. */
public void remove() { throw new UnsupportedOperationException(); }
};
}
};
}
MarkableTextView:
public class MarkableTextView extends AppCompatTextView {
public MarkableTextView(Context context) {
super(context);
}
public MarkableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MarkableTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setText(CharSequence text, BufferType type) {
// Intercept and process text
text = prepareText(text.toString());
super.setText(text, type);
}
public Spannable Markable;
private Spannable prepareText(String text) {
String parcel = text;
Multimap<String, MarkableSheet> markableSheets = ArrayListMultimap.create();
// Used to correct content position after tossing tags
int totalOffset = 0;
// Iterate through text
for (MatchResult match : matches(Markable.Patterns.XML, parcel)) {
// Get tag name
String tag = match.group(1);
// Match with a defined tag name "case-sensitive"
if (!tag.equals(Markable.Tags.MARKABLE)) {
// Break if no match
break;
}
// Extract data
String attributes = match.group(2);
String content = match.group(3);
int outset = match.start(0);
int ending = match.end(0);
int offset = totalOffset; // offset=0 since no preceded changes happened
int contentLength = match.group(3).length();
// Calculate offset for the next element
totalOffset = (ending - outset) - contentLength;
// Add to markable sheets
MarkableSheet sheet =
new MarkableSheet(attributes, content, outset, ending, offset, contentLength);
markableSheets.put(tag, sheet);
// Toss the tag and keep content
Matcher reMatcher = Markable.Patterns.XML.matcher(parcel);
parcel = reMatcher.replaceFirst(content);
}
// Initialize spannable with the modified text
Markable = new SpannableString(parcel);
// Iterate through markable sheets
for (MarkableSheet sheet : markableSheets.values()) {
// Iterate through attributes
for (MatchResult match : matches(Markable.Patterns.ATTRIBUTES, sheet.getAttributes())) {
String attribute = match.group(1);
String value = match.group(3);
// Apply styles
stylate(attribute,
value,
sheet.getOutset(),
sheet.getOffset(),
sheet.getContentLength());
}
}
return Markable;
}
Finally, styling, so here's a very simple styler i made for this answer:
public void stylate(String attribute, String value, int outset, int offset, int length) {
// Correct position
outset -= offset;
length += outset;
if (attribute.equals(Markable.Tags.TEXT_STYLE)) {
if (value.contains(Markable.Tags.BOLD) && value.contains(Markable.Tags.ITALIC)) {
Markable.setSpan(
new StyleSpan(Typeface.BOLD_ITALIC),
outset,
length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
else if (value.contains(Markable.Tags.BOLD)) {
Markable.setSpan(
new StyleSpan(Typeface.BOLD),
outset,
length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
else if (value.contains(Markable.Tags.ITALIC)) {
Markable.setSpan(
new StyleSpan(Typeface.ITALIC),
outset,
length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (value.contains(Markable.Tags.UNDERLINE)) {
Markable.setSpan(
new UnderlineSpan(),
outset,
length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
if (attribute.equals(Markable.Tags.TEXT_COLOR)) {
if (value.equals(Markable.Tags.ATTENTION)) {
Markable.setSpan(
new ForegroundColorSpan(ContextCompat.getColor(
getContext(),
R.color.colorAttention)),
outset,
length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
else if (value.equals(Markable.Tags.INTERACTION)) {
Markable.setSpan(
new ForegroundColorSpan(ContextCompat.getColor(
getContext(),
R.color.colorInteraction)),
outset,
length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
And here's how the Markable class containing the definitions looks like:
public class Markable {
public static class Patterns {
public static final Pattern XML =
Pattern.compile("<([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)(?:\\s+([^>]*))?>([^>][^<]*)</\\1\\s*>");
public static final Pattern ATTRIBUTES =
Pattern.compile("(\\S+)\\s*=\\s*(['\"])\\s*(.+?)\\s*\\2");
}
public static class Tags {
public static final String MARKABLE = "markable";
public static final String TEXT_STYLE = "textStyle";
public static final String BOLD = "bold";
public static final String ITALIC = "italic";
public static final String UNDERLINE = "underline";
public static final String TEXT_COLOR = "textColor";
public static final String ATTENTION = "attention";
public static final String INTERACTION = "interaction";
}
}
All that we need now is to reference a string and basically it should look like this:
<string name="markable_string">
<![CDATA[Hello <markable textStyle=\"underline\" textColor=\"interaction\">world</markable>!]]>
</string>
Make sure to wrap the tags with a CDATA Section and escape " with \.
I made this as a modular solution to process parts of the text in all different ways without the need of stuffing unnecessary code behind.
I did as andy boot said, but i had a clickable span as well, and it didn't work because the order the setSpans were called. So you have to first call the spannable.setSpan(clickableSpanand... then the spannable.setSpan(new ForegroundColorSpan... to get the color in the TextView
Inspired by Alejandro H. Cruz's answer above.
His function only works for a single substring match, I have updated his method to use Regex and should update colors on all matches:
fun TextView.colorizeAll(subStringToColorize: String, #ColorRes colorResId: Int) {
val color: Int = ContextCompat.getColor(context, colorResId)
val spannable: Spannable = SpannableString(text)
val pattern = subStringToColorize.toRegex()
val matches = pattern.findAll(text, 0)
matches.forEach { match ->
val startIndex = match.range.first
val endIndex = match.range.last + match.range.step
spannable.setSpan(ForegroundColorSpan(color),
startIndex,
endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
setText(spannable, TextView.BufferType.SPANNABLE)
}
}
I created this little helper method that can be called from a TextView:
fun TextView.attributedString(
forText: String,
foregroundColor: Int? = null,
style: StyleSpan? = null
) {
val spannable: Spannable = SpannableString(text)
// check if the text we're highlighting is empty to abort
if (forText.isEmpty()) {
return
}
// compute the start and end indices from the text
val startIdx = text.indexOf(forText)
val endIdx = startIdx + forText.length
// if the indices are out of bounds, abort as well
if (startIdx < 0 || endIdx > text.length) {
return
}
// check if we can apply the foreground color
foregroundColor?.let {
spannable.setSpan(
ForegroundColorSpan(it),
startIdx,
endIdx,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
}
// check if we have a stylespan
style?.let {
spannable.setSpan(
style,
startIdx,
endIdx,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
}
// apply it
text = spannable
}
To use it:
plateText.text = "Hello world!"
// This will color the part "world" to whatever color you have defined
// And make the word **bold**.
plateText.attributedString(
"world",
getColor(R.color.colorMatchingText, null),
StyleSpan(Typeface.BOLD)
)
Tested on API 29, cheers!
SpannableStringBuilder builder = new SpannableStringBuilder();
String the = "The ";
SpannableString theSpannable= new SpannableString(the);
builder.append(theSpannable);
String author = "author ";
SpannableString authorSpannable= new SpannableString(author);
authorSpannable.setSpan(new RelativeSizeSpan(1.2f), 0,authorSpannable.length(), 0); // set size
authorSpannable.setSpan(new ForegroundColorSpan(Color.BLACK), 0, authorSpannable.length(), 0);
builder.append(authorSpannable);
String has = "has ";
SpannableString hasSpannable= new SpannableString(has);
builder.append(hasSpannable);
String approved = "approved ";
SpannableString approvedSpannable= new SpannableString(approved);
approvedSpannable.setSpan(new RelativeSizeSpan(1.2f), 0,approvedSpannable.length(), 0); // set size
StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);
approvedSpannable.setSpan(boldSpan, 0, approvedSpannable.length() + 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
approvedSpannable.setSpan(new ForegroundColorSpan(ContextCompat.getColor(this, R.color.CLR_PRESSED_SAVED)), 0,
approvedSpannable.length(), 0);
builder.append(approvedSpannable);
String white = "your access to this share. Do you want re-access now?";
SpannableString whiteSpannable= new SpannableString(white);
builder.append(whiteSpannable);
_AccessStatusText.setText(builder, TextView.BufferType.SPANNABLE);
its Simple
String text = "We've sent the code to ";
String text2 = text + getEmail() + "\n\n";
Spannable spannable = new SpannableString(text2);
spannable.setSpan(new ForegroundColorSpan(Color.BLUE), text.length(), (text + getEmail()).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mBinding.textViewStatus.setText(spannable, TextView.BufferType.SPANNABLE);
DO NOT USE Html.fromHtml to avoid fragmented behavior. Spannable or SpannableStringBuilder is the best way to do this with ForegroundColorSpan or BackgroundColorSpan depending on your requirements. Html or HtmlCompat tag even with style color or background-color is not realiable as it does not work on all SDK specially on lower version such as 21, same case for emojis.
Example case:
<span style=\"background-color:red\">⬆</span>
When the Html string above converts to Spanned using HtmlCompat.fromHtml and use it in setText() the style does not work on older SDK version.
One way is to split myTextView to few separate TextViews, one of which would be only for phone code. Then controlling color of this specific TextView is pretty straight-forward.
I have a textview with autoLinks set to all. I want to skip numbers like "2018"
which are years, these numbers should not be highlighted. Is there a delimiter I can use in the text so that it skips those numbers while parsing?
Edit:
This issue happens only in Mi devices.
try this....
String s1="jan 2018,Saturday";
String replaceString=s1.replace("2018","");//replaces all occurrences of "2018" to ""
System.out.println(replaceString);
Output := jan ,Saturday.
Use Spanable String in this case to highlight Specific String.
Here is an example:
SpannableString spannableStr = new SpannableString(originalText);
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);
spannableStr.setSpan(foregroundColorSpan, 15, 30, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
spannableTextView.setText(spannableStr);
Set color and starting string index and ending index.
For more detail check this link click this link
I searched for your answer try this
private void stripUnderlines(TextView textView) {
Spannable s = new SpannableString(textView.getText());
URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
for (URLSpan span: spans) {
int start = s.getSpanStart(span);
int end = s.getSpanEnd(span);
s.removeSpan(span);
span = new URLSpanNoUnderline(span.getURL());
s.setSpan(span, start, end, 0);
}
textView.setText(s);
}
This requires a customized version of URLSpan which doesn't enable the TextPaint's "underline" property:
private class URLSpanNoUnderline extends URLSpan {
public URLSpanNoUnderline(String url) {
super(url);
}
#Override public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
}
here is the link
Try This Code :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
highlightTv();
}
protected void highlightTv(){
// Specify the text/word to highlight inside TextView
String textToHighlight = "2018";
// Construct the formatted text
String replacedWith = "<font color='green'>" + textToHighlight + "</font>";
// Get the text from TextView
String originalString = textView.getText().toString();
// Replace the specified text/word with formatted text/word
String modifiedString = originalString.replaceAll(textToHighlight,replacedWith);
// Update the TextView text
mTextView.setText(Html.fromHtml(modifiedString));
}
I want to make the string "this link" underlined and clickable, but I don't know how to achieve that.
XML file:
<string name="submitText">Before you submit, please check out <u>this link</u></string>
In my fragment:
tvSubmit.setText(Html.fromHtml(getString(R.string.submitText)));
I don't want the whole string to be clickable, only the underlined section. I cannot use a horizontal LinearLayout with 2 cells, because on smaller devices the string won't have a continues look, it will be sectioned in 2 cells.
What have I tried:
tvSubmit.setMovementMethod(LinkMovementMethod.getInstance());
Spannable sp = (Spannable) tvSubmit.getText();
ClickableSpan click = new ClickableSpan() {
#Override
public void onClick(View widget) {
showLink();
}
};
sp.setSpan(click, 0, sp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
The code above makes the whole string underlined and also the color of the text is changed into light blue.
the problem is that you are setting the span to the whole string (sp.setSpan(click, 0, sp.length()). To fix you have to set the clickable span only on the this link. I did the same thing this way:
<string name="submitText">Before you submit, please check out %1$s</string>
<string name="this_link">this link</string>
in your Activity
String thisLink = getString(R.string.thisLink);
String yourString = getString(R.string.submitText, thisLink);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(yourString);
spannableStringBuilder.setSpan(click,
startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
where startIndex and endIndex are the index of thisLink in yourString. I separated the two strings because was kind of easier to look for the indexes, especially if you have to deal with translations. To calculate the startIndex you can use yourString.indexOf(thisLink), and endIndex is startIndex + the length of thisLink. I'll leave to you the ordinary checks, (negative indexes, and everything else that could cause an IndexOutBoundException)
you can define in your strings.xml
<string name="submitText">Before you submit, please check out this link
<TextView
android:id="#+id/tvSubmit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:autoLink=#String/submitText //link the content of web
android:textColorLink="#576586" //change the color of the link
android:textColor="#555555" />
in activity
//sample
String webLinkText = <img src="https://prativas.files.wordpress.com/2013/05/screenshot-mozilla-firefox-private-browsing.png" alt="Screenshot-Mozilla Firefox (Private Browsing)" width="293" height="254" class="alignnone size-full wp-image-291" />
tvSubmit = (TextView) findViewById(R.id.tvSubmit);
tvSubmit.setText(Html.fromHtml(webLinkText)));
check here for more detailed answer
In my case i needed to have a localised string with part of it to be clickable.
What i did was to define a string in my resources (one for each locale) with the clickable part underlined, like this:
<string name="my_message">Blah blah blah <u>call us</u> blah blah.</string>
Then i created an extension to find the underlined text and add clickable span on it, like this:
fun CharSequence.makeUnderlineClickable(listener: (index: Int) -> Unit): SpannableString {
val spannedString = SpannableString(this)
spannedString.getSpans(0, length, UnderlineSpan::class.java)?.forEachIndexed { index, underlineSpan ->
val clickableSpan = object : ClickableSpan() {
override fun onClick(widget: View) {
listener.invoke(index)
}
override fun updateDrawState(ds: TextPaint) {
ds.isUnderlineText = true
}
}
spannedString.setSpan(
clickableSpan,
spannedString.getSpanStart(underlineSpan),
spannedString.getSpanEnd(underlineSpan),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
return spannedString
}
You can use it like this:
textView.text = resources.getText(R.string.my_message).makeUnderlineClickable { index ->
//handle click here
}
textView.movementMethod = LinkMovementMethod.getInstance()
textView.highlightColor = Color.TRANSPARENT
just made this function to help me append clickable text to textview :
public static SpannableStringBuilder getSpannablableClickFor(CharSequence initialText, ClickableSpan click, String textToAppend) {
String description = String.format("%s %s", initialText, textToAppend);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(description);
int start = description.indexOf(textToAppend);
int end = start + textToAppend.length();
spannableStringBuilder.setSpan(click,
start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableStringBuilder.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableStringBuilder.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
final ForegroundColorSpan fcs = new ForegroundColorSpan(Color.WHITE);
spannableStringBuilder.setSpan(fcs, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableStringBuilder;
}
You can try the Kotlin extension function to create text-like and also clickable with an underline.
fun TextView.colorSpannableStringWithUnderLineOne(
prefixString: String,
postfixString: String,
callback: (Int) -> Unit
) {
val spanTxt = SpannableStringBuilder()
spanTxt.append("$prefixString ")
spanTxt.append(" $postfixString")
spanTxt.setSpan(object : ClickableSpan() {
override fun onClick(widget: View) {
callback(0)
widget.invalidate()
}
override fun updateDrawState(ds: TextPaint) {
ds.color = ContextCompat.getColor(context, R.color.highlight)
ds.isUnderlineText = true
}
}, prefixString.length, spanTxt.length, 0)
this.movementMethod = LinkMovementMethod.getInstance()
this.setText(spanTxt, TextView.BufferType.SPANNABLE)
}
`
How to use this:
textViewLink.colorSpannableStringWithUnderLineOne(
"Normal string",
"Clickable string",
callback = {
JLog.e("==>","Clicked")
})
textViewLink.invalidate()
sp.setSpan(click, 0, sp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
change value 0 : with position begin link in text, example change value with : 10
if you set 0 it will hyperlink all the text.
Is there any way I can launch an activity from a portion of a string.
eg
I have this in my strings.xml file:
<string name="clickable_string">This is a <u>clickable string</u></string>
I would like the text between the u tags to be underlined and launch an activity when clicked when inserted in to a TextView
Try this,
final Context context = ... // whereever your context is
CharSequence sequence = Html.fromSource(context.getString(R.string.clickable_string));
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
UnderlineSpan[] underlines = strBuilder.getSpans(UnderlineSpan.class);
for(UnderlineSpan span : underlines) {
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan myActivityLauncher = new ClickableSpan() {
public void onClick(View view) {
context.startActivity(getIntentForActivityToStart());
}
};
strBuilder.setSpan(myActivityLauncher, start, end, flags);
}
TextView textView = ...
textView.setText(strBuilder);
textView.setMovementMethod(LinkMovementMethod.getInstance());
Basically you have to attach a Span object to the range of characters you want to be clickable. Since you are using HTML anyways, you can use the underline spans placed by the Html.fromSource() as markers for your own spans.
Alternatively you could also define a Tag within the string that only you know of.
i.e. <activity>
And supply your own tag handler to the Html.fromSource() method. This way your TagHandler instance could do something like, surround the tagged text with a specific color, underline, bold and make it clickable. However I would only recommend the TagHandler approach if you find yourself writing this type of code a lot.
assign this string to one of your xml layout and then in your code get the id of TextView and then implement OnClickListener for this Textview,inside of it you can start your new activity you want.
Answered here Make parts of textview clickable (not url)
I just made a modification if you want to use it with a HTML Message do the following
In your Display function
public void displayText(String message) {
chapterTextView.setText(Html.fromHtml(message),TextView.BufferType.SPANNABLE);
chapterTextView.setMovementMethod(LinkMovementMethod.getInstance());
Spannable clickableMessage = (Spannable) chapterTextView.getText();
chapterTextView.setText(addClickablePart(clickableMessage), BufferType.SPANNABLE);
}
The Modified function of addClickablePart
private SpannableStringBuilder addClickablePart(Spannable charSequence) {
SpannableStringBuilder ssb = new SpannableStringBuilder(charSequence);
int idx1 = charSequence.toString().indexOf("(");
int idx2 = 0;
while (idx1 != -1) {
idx2 = charSequence.toString().indexOf(")", idx1) + 1;
final String clickString = charSequence.toString().substring(idx1, idx2);
ssb.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
Toast.makeText(getActivity(), clickString,
Toast.LENGTH_SHORT).show();
}
}, idx1, idx2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
idx1 = charSequence.toString().indexOf("(", idx2);
}
return ssb;
}
Hope this help someone.