5

I used to be able to do this:

<string name="foo">white <font fgcolor="#ff6890a5">blue</font></string>

But now it doesn't work any more. It seems to be a bug in the integer parsing code; see https://code.google.com/p/android/issues/detail?id=58192

Problem is, I'm getting customer complaints now; I can't wait for the bug to be fixed.

Does anybody know a work-around, such as using named resources from color.xml or something like that?

ETA: I've discovered fgcolor="blue" still works, but it's the wrong shade of blue. Is there a list of legal color names somewhere? Maybe I could find one that's close enough. It also works if the color is a number without the high bit set, like #7f6890a5, but of course that's too faint to be useful; I need a solid color, not semi-transparent.

ETA: browsing source code shows these colors:

  aqua      0x00FFFF
  black     0x000000
  blue      0x0000FF
  fuchsia   0xFF00FF
  green     0x008000
  grey      0x808080
  lime      0x00FF00
  maroon    0x800000
  navy      0x000080
  olive     0x808000
  purple    0x800080
  red       0xFF0000
  silver    0xC0C0C0
  teal      0x008080
  white     0xFFFFFF
  yellow    0xFFFF00

This doesn't fix my problem, but perhaps other people searching on this question could find this information useful.

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • Looking at the code, the fgcolor="@color/color_name" reference mechanism should work, but only for colors in the system namespace (http://developer.android.com/reference/android/R.color.html). – Joe Sep 16 '13 at 23:52
  • More FYI, I think using some color names from the above list (aqua, fuchsia, etc. - those that were [added in the commit](https://github.com/android/platform_frameworks_base/commit/a8f6d5f0720f400b6f59b0809aaefea83c5f51d4)) will also not work since they all are missing the alpha values. – Joe Sep 17 '13 at 19:11

3 Answers3

11

How about we leverage the fact that colors without the high bit set still works and just replace it with the correct colors? So you can have a method like this:

private CharSequence fixSpanColor(CharSequence text) {
    if (text instanceof Spanned) {
        final SpannableString s = new SpannableString(text);
        final ForegroundColorSpan[] spans = s.getSpans(0, s.length(), ForegroundColorSpan.class);
        for (final ForegroundColorSpan oldSpan : spans) {
            final ForegroundColorSpan newSpan = new ForegroundColorSpan(oldSpan.getForegroundColor() | 0xFF000000);
            s.setSpan(newSpan, s.getSpanStart(oldSpan), s.getSpanEnd(oldSpan), s.getSpanFlags(oldSpan));
            s.removeSpan(oldSpan);
        }
        return s;
    } else {
        return text;
    }
}

You will then need to pass any text with the required color accent through this method, the simplest example would be modifying all calls like this:

tv.setText(getText(R.string.foo));

To:

tv.setText(fixSpanColor(getText(R.string.foo)));

Hopefully, depending on how your code is structured, there might already a central place where you can add this extra method call.

Joe
  • 14,039
  • 2
  • 39
  • 49
  • I basically looked at the framework commit that was mentioned in the bug report which should give enough background information (IMHO, the bug can be fixed by modifying line 339 in StringBlock.java in the commit to `c |= Color.getHtmlColor(color)` instead of `c = Color.getHtmlColor(color)`): https://github.com/android/platform_frameworks_base/commit/a8f6d5f0720f400b6f59b0809aaefea83c5f51d4 – Joe Sep 17 '13 at 19:00
  • Did you get the bounty? I accepted your answer, but maybe there was something else I had to do. – Edward Falk Sep 21 '13 at 19:55
  • 1
    I like this solution, just though I'd mention another workaround (not to be used in production): `` (this is `-ff6890a5`, flipping the sign moves the number below `80000000`) – TWiStErRob Sep 04 '14 at 20:58
  • Note about this solution: make sure to take off the alpha section "FF" part of the ARGB value on fgcolor. Or at least make it "00". – Adam Johns Dec 17 '14 at 16:16
  • You can't leave out the alpha value. Setting it to zero (or leaving it out) makes the text completely transparent; i.e. invisible. – Edward Falk Oct 14 '15 at 22:38
  • Please add a note that getString() will not working and should use getText() method. – Muhammad Helmi Feb 23 '21 at 09:51
4

I have some awful workaround in my client code to manually reset the ForegroundColorSpans to the proper color, but it would be great not to have to do so.

I think the workaround that the issue reporter's talking about is the following:

Define the string as:

<string name="foo">white blue</string>

In your activity:

TextView tv = (TextView) findViewById(R.id.textView1);

SpannableString spannableString = new 
                       SpannableString(getResources().getString(R.string.foo));

ForegroundColorSpan fcs = new 
                       ForegroundColorSpan(getResources().getColor(R.color.bluish));

spannableString.setSpan(fcs, spannableString.toString().indexOf(" ") + 1,
                       spannableString.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);

tv.setText(spannableString);

R.color.bluish is defined as <color name="bluish">#ff6890a5</color>.

But, using " " (space) to distinguish and apply the ForegroundColorSpan would only be practical if you have a small number of strings defined.


The following modification might actually be easier for you to carry out:

Define the string as:

<string name="foo_sep_1"><![CDATA[white <font color=\"#6890a5\">blue</font>]]></string>

Or:

<string name="foo_sep_1">white &lt;font color="#6890a5"&gt;blue&lt;/font&gt;</string>

In your activity:

TextView tv2 = (TextView) findViewById(R.id.textView2);

tv2.setText(Html.fromHtml(getResources().getString(R.string.foo_sep_1)));

Be careful about the color code: HTML color codes do not have alpha values (RRGGBB will work, AARRGGBB will not)


Another workaround is using Html.fromHtml(String) directly:

TextView tv3 = (TextView) findViewById(R.id.textView3);

tv3.setText(Html.fromHtml("white <font color='#6890a5'>blue</font>"));
Vikram
  • 51,313
  • 11
  • 93
  • 122
0

Kudos to TWiStErRob who found a solution that doesn't involve code in https://stackoverflow.com/a/11577658/338479. To quote:

for any color above 7fffffff apply the following: <font color="#ff6890a5"> put ff6890a5 into a calculator (optionally convert to decimal first) and flip the sign, then (optionally convert back to hexa) take the last 8 hexadecimal digits and use <font color="-#00976F5B">.

Community
  • 1
  • 1
Edward Falk
  • 9,991
  • 11
  • 77
  • 112