Reputation: 308
I've been trying a whole day to get this to work. I've done this before but lost the source code when my drive crashed. The call:
textView.setText(getSpannableString("1Blue 2Red 5Green", false, MainActivity.this));
Should put the text Blue Red Green coloured in respective colours in the textview. But for some reason only the last 'e' in "Blue" turns blue, last 'd' in "Red" and last 'n' in "Green" have the right colour. Anyone can spot my mistake? The idea is to put a colorspan on each character.
public static SpannableString getSpannableString(String text, Boolean startWithGrey, Context context) {
String cutText=text.replace("0","").replace("1","").replace("2","").replace("5","");
int pos = 0;
ForegroundColorSpan fcs;
int colour;
SpannableString span = new SpannableString(cutText);
if (!startWithGrey){
colour=0;
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_0));
} else {
colour=3;
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_3));
}
for (int i = 0; i < text.length(); i++) {
switch (text.charAt(i)) {
case '0':
if (!startWithGrey){
colour=0;
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_0));
} else {
colour=3;
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_3));
}
break;
case '1':
colour = 1;
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_1));
break;
case '2':
colour = 2;
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_2));
break;
case '5':
colour = 5;
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_5));
break;
default:
span.setSpan(fcs, pos, pos+1 , Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
pos++;
break;
}
}
return span;
}
And in color.xml:
<color name="text_colour_0">#000000</color>
<color name="text_colour_1">#0000FF</color>
<color name="text_colour_2">#FF0000</color>
<color name="text_colour_3">#A8A8A8</color>
<color name="text_colour_5">#00FF00</color>
Upvotes: 0
Views: 2069
Reputation: 308
Ok guys, thanks alot for the help. I couldn't use your code snippets but they did help me understand what I was doing wrong. I merely moved the colorspan one character at a time, until I created a new colorspan and moved that one a character at a time. That's why only the last character in each was coloured. So I intruduced a new variable: start. The start of each colorspan. I ended up with this. I know you fancy coders could do this in about a fifth of the lines I'm using. I'm not a fancy coder but at least it works now! Thanks again!
public static SpannableString getSpannableString(String text, Boolean startWithGrey, Context context) {
if (text != null) {
String cutText = text.replace("@", "").replace("%", "").replace("0", "").replace("1", "").replace("2", "").replace("3", "").replace("4", "").replace("5", "");
text = text.replace("@", "").replace("%", "");
int pos = 0;
int start = 0;
ForegroundColorSpan fcs;
SpannableString span = new SpannableString(cutText);
if (!startWithGrey) {
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_0));
} else {
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_3));
}
for (int i = 0; i < text.length(); i++) {
switch (text.charAt(i)) {
case '0':
if (!startWithGrey) {
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_0));
} else {
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_3));
}
start = pos;
break;
case '1':
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_1));
start = pos;
break;
case '2':
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_2));
start = pos;
break;
case '3':
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_3));
start = pos;
break;
case '4':
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_4));
start = pos;
break;
case '5':
fcs = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.text_colour_5));
start = pos;
break;
default:
span.setSpan(fcs, start, pos + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
pos++;
break;
}
}
return span;
} else {
return new SpannableString("");
}
}
Upvotes: 0
Reputation: 111
Hope this code snippets will help you
private SpannableString getSpannableString(String text) {
SpannableString spannableString = new SpannableString(text);
String[] splitString = text.split(" ");
for (String s : splitString) {
int startIndex = text.indexOf(s);
int endIndex = startIndex + s.length();
switch (s.toLowerCase()) {
case "red":
spannableString.setSpan(new ForegroundColorSpan(Color.RED),startIndex,endIndex,SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
break;
case "green" :
spannableString.setSpan(new ForegroundColorSpan(Color.GREEN),startIndex,endIndex,SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
break;
case "blue":
spannableString.setSpan(new ForegroundColorSpan(Color.BLUE),startIndex,endIndex,SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
break;
}
}
return spannableString;
}
usage ::
txtview.setText(getSpannableString("Red Green Blue"));
Upvotes: 2
Reputation: 2318
The problem is since you are using a loop to go character by character and this line here
span.setSpan(fcs, pos, pos+1 , Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Whenever this hits, it is not like all previous data of the loop remains, so only the last character in your word is there in the loop at that moment and this only last character gets the span applied to it.
I would suggest you use SpannableStringBuilder
and you can simply set the span to whole the text instead of going character by character. I hope this clarifies things for you.
Edit: I am adding a Kotlin solution for this. Since I use Kotlin mostly, but the same can be converted into Java, might need some looking into though.
fun getSpannable(inputText: String): SpannableStringBuilder {
val splitString = inputText.split(" ") // Split string using delimiter.
val spanBuilder = SpannableStringBuilder()
splitString.forEach { split ->
val start = spanBuilder.length // Start is the current length of the spanBuilder.
spanBuilder.append(split.subSequence(1, split.length)) // We append a substring of our split string thus removing the number at front.
when (split[0].toString().toInt()) { // Extract the number at front and compare it and set span.
1 -> spanBuilder.setSpan(ForegroundColorSpan(Color.RED), start, spanBuilder.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
2 -> spanBuilder.setSpan(ForegroundColorSpan(Color.BLUE), start, spanBuilder.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
3 -> spanBuilder.setSpan(ForegroundColorSpan(Color.GREEN), start, spanBuilder.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
return spanBuilder
}
And then you can set it as follows
textView.setText(getSpannable("1Red 2Blue 3Green"), TextView.BufferType.SPANNABLE)
Upvotes: 1