I have textview in which i want to display html which i get from a server so i use like this
Spanned html = Html.fromHtml(content.toString(), Html.FROM_HTML_MODE_COMPACT);
but it did not display well because the span did not remove the white spaces, so i tried this
int i = html.length();
while(--i >= 0) {
char test = html.charAt(i);
if (test != 0 && !Character.isWhitespace(test)){
break;
}
}
and this
CharSequence sub = (html.subSequence(0, descriptionWithOutExtraSpace.length()))
and this
String withSpace = html.toString();
String descriptionWithOutExtraSpace = new String(html.toString()).trim();
but all came to the same part that the spaces is removed but it isn't html any more and for example a url is not linked any more
some one have any recommendation for me?
in the and i did it like this
Spanned html = Html.fromHtml(content.toString(), Html.FROM_HTML_MODE_COMPACT);
String descriptionWithOutExtraSpace = new String(html.toString()).trim();
CharSequence sub = (html.subSequence(0, descriptionWithOutExtraSpace.length()));
holder.binding.contentView.setText(sub);}
Related
I have a TextView and contains the below text
The -[[community]]- is here to help you with -[[specific]]- coding, -[[algorithm]]-, or -[[language]]- problems.
I want anything inside -[[]]- take red color, How can I do that using Spannable?
And I don't want to show -[[ and ]]- in TextView
You can use SpannableStringBuilder and append parts of String colorizing them when necessary. For example,
static CharSequence colorize(
String input, String open, String close, #ColorInt int color
) {
SpannableStringBuilder builder = new SpannableStringBuilder();
int openLen = open.length(), closeLen = close.length();
int openAt, contentAt, closeAt, last = 0;
while ((openAt = input.indexOf(open, last)) >= 0 &&
(closeAt = input
.indexOf(close, contentAt = openAt + openLen)) >= 0) {
int start = builder.append(input, last, openAt).length();
int len = builder.append(input, contentAt, closeAt).length();
builder.setSpan(
new ForegroundColorSpan(color),
start, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
);
last = closeAt + closeLen;
}
return builder.append(input, last, input.length());
}
You can use the CodeView library to highlight many patterns with different colors, in your case for example the code will be like this
CodeView codeView = findViewById(R.id.codeview);
codeView.addSyntaxPattern(Pattern.compile("-\\[\\[[a-zA-Z]+]]-"), Color.GREEN);
codeView.setTextHighlighted(text);
And the result will be:
If the highlighted keywords are unique you can highlight them without using -[[]]- just create a pattern that can cover them
You can change the color, add or remove patterns in the runtime
CodeView Repository URL: https://github.com/amrdeveloper/codeview
The value in the variable who named open must be different from the value in the variable who named close, If the value was the same will cause a problem. You need to change variables values only to work well.
String open = "-[[";
String close = "]]-";
int color = Color.RED;
String s1 = "The -[[community]]- is here to help you with -[[specific]]- coding, -[[algorithm]]-, or -[[language]]- problems.";
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(s1);
while (spannableStringBuilder.toString().contains(open) && spannableStringBuilder.toString().contains(close)) {
spannableStringBuilder.setSpan(new ForegroundColorSpan(color), spannableStringBuilder.toString().indexOf(open) + open.length(), spannableStringBuilder.toString().indexOf(close) + close.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableStringBuilder.replace(spannableStringBuilder.toString().indexOf(open), spannableStringBuilder.toString().indexOf(open) + open.length(), "").replace(spannableStringBuilder.toString().indexOf(close), spannableStringBuilder.toString().indexOf(close) + close.length(), "");
}
yourTextView.setText(spannableStringBuilder);
I am working on an android project that involves parsing some HTML (parsed by Jsoup) into a SpannableStringBuilder class.
However, I need this SpannableStringBuilder class to be divided up by each new line character into a List once it is done parsing, while keeping its formatting.
Such that a spanned text of
{"I am a spanned text,\n hear me roar"}
would turn into
{
"I am a spanned text,"
"hear me roar"
}
I am fairly new to developing on Android, and could not find anything in the documentation about spitting spans or even getting a listing of all formatting on a spanned class to build my own. So any help is much appreciated.
I managed to figure this out on my own, after looking into the method that pskink suggested.
My solution to this was
#Override
public List<Spanned> parse() {
List<Spanned> spans = new ArrayList<Spanned>();
Spannable unsegmented = (Spannable) Html.fromHtml(base.html(), null, new ReaderTagHandler());
//Set ColorSpan because it defaults to white text color
unsegmented.setSpan(new ForegroundColorSpan(Color.BLACK), 0, unsegmented.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//get locations of '/n'
Stack<Integer> loc = getNewLineLocations(unsegmented);
loc.push(unsegmented.length());
//divides up a span by each new line character position in loc
while (!loc.isEmpty()) {
Integer end = loc.pop();
Integer start = loc.isEmpty() ? 0 : loc.peek();
spans.add(0,(Spanned) unsegmented.subSequence(start, end));
}
return spans;
}
private Stack<Integer> getNewLineLocations(Spanned unsegmented) {
Stack<Integer> loc = new Stack<>();
String string = unsegmented.toString();
int next = string.indexOf('\n');
while (next > 0) {
//avoid chains of newline characters
if (string.charAt(next - 1) != '\n') {
loc.push(next);
next = string.indexOf('\n', loc.peek() + 1);
} else {
next = string.indexOf('\n', next + 1);
}
if (next >= string.length()) next = -1;
}
return loc;
}
How to display unicode character in TextView in Android using RubyMotion?
I tried
MainModule.get.setText('\u00d7')
MainModule.get.setText('0x00d7')
Where get is to get the TextView object.
But neither works, it still displays the original string(\u00d7 or 0x00d7).
Edit
I am using Ruby to write Android, not Java.
I get you a method that unicode to string, I hole that would be useful for you.
mTextView.setText(unicode2String("\\u00d7"));
...
public String unicode2String(String unicode) {
StringBuffer string = new StringBuffer();
String[] hex = unicode.split("\\\\u");
for (int i = 1; i < hex.length; i++) {
int data = Integer.parseInt(hex[i], 16);
string.append((char) data);
}
return string.toString();
}
Is it possible to parse HTML code in a verbatim mode or something similar so that the source code fragments that eventually may appear (enclosed between pre and code HTML tags) can be displayed properly?
What I want to do is show source code in a user-friendly mode (easy to distinguish from the rest of the text, keep indentation, etc.), as Stack Overflow does :)
It seems that Html.fromHtml() supports only a reduced subset of HTML tags.
TextView will never succeed supporting all the html formating and styling you would want it to. Use WebView instead.
TextView is native and more lightweight, but exactly because of its lightweightedness it will not understand some of the directives you describe.
Finally I preparsed by myself the HTML code received, since Html.fromHtml does not support the pre and code tags, y replaced them with my custom format and pre-parsed the code inside those tags replacing "\n" with <br/> and " " with .
Then I send the results to Html.fromHtml, and the result is just fine:
public class HtmlParser {
public static Spanned parse(String text) {
if (text == null) return null;
text = parseSourceCode(text);
Spanned textSpanned = Html.fromHtml(text);
return textSpanned;
}
private static String parseSourceCode(String text) {
if (text.indexOf(ORIGINAL_PATTERN_BEGIN) < 0) return text;
StringBuilder result = new StringBuilder();
int begin;
int end;
int beginIndexToProcess = 0;
while (text.indexOf(ORIGINAL_PATTERN_BEGIN) >= 0) {
begin = text.indexOf(ORIGINAL_PATTERN_BEGIN);
end = text.indexOf(ORIGINAL_PATTERN_END);
String code = parseCodeSegment(text, begin, end);
result.append(text.substring(beginIndexToProcess, begin));
result.append(PARSED_PATTERN_BEGIN);
result.append(code);
result.append(PARSED_PATTERN_END);
//replace in the original text to find the next appearance
text = text.replaceFirst(ORIGINAL_PATTERN_BEGIN, PARSED_PATTERN_BEGIN);
text = text.replaceFirst(ORIGINAL_PATTERN_END, PARSED_PATTERN_END);
//update the string index to process
beginIndexToProcess = text.lastIndexOf(PARSED_PATTERN_END) + PARSED_PATTERN_END.length();
}
//add the rest of the string
result.append(text.substring(beginIndexToProcess, text.length()));
return result.toString();
}
private static String parseCodeSegment(String text, int begin, int end) {
String code = text.substring(begin + ORIGINAL_PATTERN_BEGIN.length(), end);
code = code.replace(" ", " ");
code = code.replace("\n","<br/>");
return code;
}
private static final String ORIGINAL_PATTERN_BEGIN = "<pre><code>";
private static final String ORIGINAL_PATTERN_END = "</code></pre>";
private static final String PARSED_PATTERN_BEGIN = "<font color=\"#888888\"><tt>";
private static final String PARSED_PATTERN_END = "</tt></font>";
}
I am taking Spanned Text from an EditText box and converting it to a HTML tagged string using HTML.toHtml. This works fine. I have verified that the string is correct and contains a <br> in the appropriate location. However, when I got to convert the tagged string back to a spanned text to populate a TextView or EditText using HTML.fromHtml the <br> (or multiple ones if they are present) at the end of the first paragraph disappear. This means that if a users entered text with multiple line breaks and wanted to keep that formatting it gets lost.
I attached a picture to help illustrate this. The first EditText is the user input, the TextView Below it is the HTML.tohtml result of the EditText above it, the EditText below it is populated using HTML.fromHtml using the string in the TextView above it. As you can see the line breaks have disappeared and so have the extra lines. Furthermore, when the spanned text of the second edit text is run through the HTML.toHtml it now produces a different HTML tagged String.
I would like to be able to take the HTML tagged String from the first EditText and populate other TextViews or EditTexts without losing line breaks and formatting.
I also had this problem and I could not find an easy "transform" or something alike solution. Note something important, when the user presses "enter" java produces the special character \n but in HTML there is no such format for line breaking. It is the <br />.
So what I have done was to replace some specific CharSequences, from the plain text, by the alternative HTML format. In my case there was only the "enter" character so it was not that messy.
I had similar problem when I was trying to save/restore editText content to db. The problem is in Html.toHtml, it somehow skips line brakes:
String src = "<p dir=\"ltr\">First line</p><p dir=\"ltr\">Second<br/><br/><br/></p><p dir=\"ltr\">Third</p>";
EditText editText = new EditText(getContext());
// All line brakes are correct after this
editText.setText(new SpannedString(Html.fromHtml(src)));
String result = Html.toHtml(editText.getText()); // Here breaks are lost
// Output :<p dir="ltr">First line</p><p dir="ltr">Second<br></p><p dir="ltr">Third</p>
I've solved this by using custom toHtml function to serialize spanned text, and replaced all '\n' with "< br/>:
public class HtmlParser {
public static String toHtml(Spannable text) {
final SpannableStringBuilder ssBuilder = new SpannableStringBuilder(text);
int start, end;
// Replace Style spans with <b></b> or <i></i>
StyleSpan[] styleSpans = ssBuilder.getSpans(0, text.length(), StyleSpan.class);
for (int i = styleSpans.length - 1; i >= 0; i--) {
StyleSpan span = styleSpans[i];
start = ssBuilder.getSpanStart(span);
end = ssBuilder.getSpanEnd(span);
ssBuilder.removeSpan(span);
if (span.getStyle() == Typeface.BOLD) {
ssBuilder.insert(start, "<b>");
ssBuilder.insert(end + 3, "</b>");
} else if (span.getStyle() == Typeface.ITALIC) {
ssBuilder.insert(start, "<i>");
ssBuilder.insert(end + 3, "</i>");
}
}
// Replace underline spans with <u></u>
UnderlineSpan[] underSpans = ssBuilder.getSpans(0, ssBuilder.length(), UnderlineSpan.class);
for (int i = underSpans.length - 1; i >= 0; i--) {
UnderlineSpan span = underSpans[i];
start = ssBuilder.getSpanStart(span);
end = ssBuilder.getSpanEnd(span);
ssBuilder.removeSpan(span);
ssBuilder.insert(start, "<u>");
ssBuilder.insert(end + 3, "</u>");
}
replace(ssBuilder, '\n', "<br/>");
return ssBuilder.toString();
}
private static void replace(SpannableStringBuilder b, char oldChar, String newStr) {
for (int i = b.length() - 1; i >= 0; i--) {
if (b.charAt(i) == oldChar) {
b.replace(i, i + 1, newStr);
}
}
}
}
Also it turned out that this way is faster in about 4 times that default Html.toHtml(): I've made a benchmark with about 20 pages and 200 spans:
Editable ed = editText.getText(); // Here is a Tao Te Ching :)
String result = "";
DebugHelper.startMeasure("Custom");
for (int i = 0; i < 10; i++) {
result = HtmlParserHelper.toHtml(ed);
}
DebugHelper.stopMeasure("Custom"); // 19 ms
DebugHelper.startMeasure("Def");
for (int i = 0; i < 10; i++) {
result = Html.toHtml(ed);
}
DebugHelper.stopMeasure("Def"); // 85 ms
Replace /n => < br>< br>
example
< p>hi< /p>
< p>j< /p>
to:
< p>hi< /p>< br>< br>< p>j< /p>