My use case was converting a TextView's contents, including color and style, to/from a hex string. Building off Dan's answer, I came up with the following code. Hopefully if someone has a similar use case, it'll save you some headache.
Store textBox's contents to string:
String actualText = textBox.getText().toString();
SpannableString spanStr = new SpannableString(textBox.getText());
ForegroundColorSpan[] fSpans = spanStr.getSpans(0,spanStr.length(),ForegroundColorSpan.class);
StyleSpan[] sSpans = spanStr.getSpans(0,spanStr.length(),StyleSpan.class);
int nSpans = fSpans.length;
String spanInfo = "";
String headerInfo = String.format("%08X",nSpans);
for (int i = 0; i < nSpans; i++) {
spanInfo += String.format("%08X",fSpans[i].getForegroundColor());
spanInfo += String.format("%08X",spanStr.getSpanStart(fSpans[i]));
spanInfo += String.format("%08X",spanStr.getSpanEnd(fSpans[i]));
}
nSpans = sSpans.length;
headerInfo += String.format("%08X",nSpans);
for (int i = 0; i < nSpans; i++) {
spanInfo += String.format("%08X",sSpans[i].getStyle());
spanInfo += String.format("%08X",spanStr.getSpanStart(sSpans[i]));
spanInfo += String.format("%08X",spanStr.getSpanEnd(sSpans[i]));
}
headerInfo += spanInfo;
headerInfo += actualText;
return headerInfo;
Retrieve textBox's contents from string:
String header = tvString.substring(0,8);
int fSpans = Integer.parseInt(header,16);
header = tvString.substring(8,16);
int sSpans = Integer.parseInt(header,16);
int nSpans = fSpans + sSpans;
SpannableString tvText = new SpannableString(tvString.substring(nSpans*24+16));
tvString = tvString.substring(16,nSpans*24+16);
int cc, ss, ee;
int begin;
for (int i = 0; i < fSpans; i++) {
begin = i*24;
cc = (int) Long.parseLong(tvString.substring(begin,begin+8),16);
ss = (int) Long.parseLong(tvString.substring(begin+8,begin+16),16);
ee = (int) Long.parseLong(tvString.substring(begin+16,begin+24),16);
tvText.setSpan(new ForegroundColorSpan(cc), ss, ee, 0);
}
for (int i = 0; i < sSpans; i++) {
begin = i*24+fSpans*24;
cc = (int) Long.parseLong(tvString.substring(begin,begin+8),16);
ss = (int) Long.parseLong(tvString.substring(begin+8,begin+16),16);
ee = (int) Long.parseLong(tvString.substring(begin+16,begin+24),16);
tvText.setSpan(new StyleSpan(cc), ss, ee, 0);
}
textBox.setText(tvText);
The reason for the (int) Long.parseLong in the retrieval code is because the style/color can be negative numbers. This trips up parseInt and results in an overflow error. But, doing parseLong and then casting to int gives the correct (positive or negative) integer.
toHtml()
is perfectly functional, but slow. I have a bunch of formatted text to display that rarely changes. I'm loading it all up from saved storage as Strings but I need to runtoHTML
on each of one of them before I can runsetText
to display them to the user. The conversion from String to Spanned is the real bottleneck and I'm trying to figure out how to save the work I've done instead of recalculating every time. – Bearden