jan*_*ver 43 html android textview
我正在尝试为留言板构建一个Android应用程序.要显示帖子内容的格式化html,我选择了TextView和Html.fromHtml()方法.遗憾的是,这只涵盖了几个html标签.未知标记由实现TagHandler的类处理,并且必须由我自己生成.
现在,我搜索了很多,无法找到这个类应该如何工作的例子.让我们考虑我有一个用于标记某些文本的u标记(我知道这已被弃用,但无论如何).我的TagHandler看起来如何?
它以下列方式调用:
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
Run Code Online (Sandbox Code Playgroud)
前两个论点都没问题.我想我必须使用output.append()修改输出.但是我如何附上在那里加下划线的东西呢?
jan*_*ver 100
所以,我终于自己弄明白了.
public class MyHtmlTagHandler implements TagHandler {
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if(tag.equalsIgnoreCase("strike") || tag.equals("s")) {
processStrike(opening, output);
}
}
private void processStrike(boolean opening, Editable output) {
int len = output.length();
if(opening) {
output.setSpan(new StrikethroughSpan(), len, len, Spannable.SPAN_MARK_MARK);
} else {
Object obj = getLast(output, StrikethroughSpan.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != len) {
output.setSpan(new StrikethroughSpan(), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
private Object getLast(Editable text, Class kind) {
Object[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
} else {
for(int i = objs.length;i>0;i--) {
if(text.getSpanFlags(objs[i-1]) == Spannable.SPAN_MARK_MARK) {
return objs[i-1];
}
}
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于TextView,您可以将其称为:
myTextView.setText (Html.fromHtml(text.toString(), null, new MyHtmlTagHandler()));
Run Code Online (Sandbox Code Playgroud)
如果有人需要它.
干杯
Cha*_*ham 11
在android.text.html.596 - 626行.复制/粘贴
private static <T> Object getLast(Spanned text, Class<T> kind) {
/*
* This knows that the last returned object from getSpans()
* will be the most recently added.
*/
Object[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
} else {
return objs[objs.length - 1];
}
}
private static void start(SpannableStringBuilder text, Object mark) {
int len = text.length();
text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
}
private static <T> void end(SpannableStringBuilder text, Class<T> kind,
Object repl) {
int len = text.length();
Object obj = getLast(text, kind);
int where = text.getSpanStart(obj);
text.removeSpan(obj);
if (where != len) {
text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
Run Code Online (Sandbox Code Playgroud)
要使用,请覆盖TagHandler,如下所示:
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
if(tag.equalsIgnoreCase("strike") || tag.equals("s")) {
if(opening){
start((SpannableStringBuilder) output, new Strike();
} else {
end((SpannableStringBuilder) output, Strike.class, new StrikethroughSpan());
}
}
}
/*
* Notice this class. It doesn't really do anything when it spans over the text.
* The reason is we just need to distinguish what needs to be spanned, then on our closing
* tag, we will apply the spannable. For each of your different spannables you implement, just
* create a class here.
*/
private static class Strike{}
Run Code Online (Sandbox Code Playgroud)
我接受了 janoliver 的回答,并提出了我的版本,试图支持更多选项
String text = ""; // HTML text to convert
// Preprocessing phase to set up for HTML.fromHtml(...)
text = text.replaceAll("<span style=\"(?:color: (#[a-fA-F\\d]{6})?; )?(?:font-family: (.*?); )?(?:font-size: (.*?);)? ?\">(.*?)</span>",
"<font color=\"$1\" face=\"$2\" size=\"$3\">$4</font>");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )face=\"'(.*?)', .*?\"", "face=\"$1\"");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"xx-small\"", "$1size=\"1\"");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"x-small\"", "$1size=\"2\"");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"small\"", "$1size=\"3\"");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"medium\"", "$1size=\"4\"");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"large\"", "$1size=\"5\"");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"x-large\"", "$1size=\"6\"");
text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"xx-large\"", "$1size=\"7\"");
text = text.replaceAll("<strong>(.*?)</strong>", "<_em>$1</_em>"); // we use strong for bold-face
text = text.replaceAll("<em>(.*?)</em>", "<strong>$1</strong>"); // and em for italics
text = text.replaceAll("<_em>(.*?)</_em>", "<em>$1</em>"); // but Android uses em for bold-face
text = text.replaceAll("<span style=\"background-color: #([a-fA-F0-9]{6}).*?>(.*?)</span>", "<_$1>$2</_$1>");
text_view.setText(Html.fromHtml(text, null, new Html.TagHandler() {
private List<Object> _format_stack = new LinkedList<Object>();
@Override
public void handleTag(boolean open_tag, String tag, Editable output, XMLReader _) {
if (tag.startsWith("ul"))
processBullet(open_tag, output);
else if (tag.matches(".[a-fA-F0-9]{6}"))
processBackgroundColor(open_tag, output, tag.substring(1));
}
private void processBullet(boolean open_tag, Editable output) {
final int length = output.length();
if (open_tag) {
final Object format = new BulletSpan(BulletSpan.STANDARD_GAP_WIDTH);
_format_stack.add(format);
output.setSpan(format, length, length, Spanned.SPAN_MARK_MARK);
} else {
applySpan(output, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
private void processBackgroundColor(boolean open_tag, Editable output, String color) {
final int length = output.length();
if (open_tag) {
final Object format = new BackgroundColorSpan(Color.parseColor('#' + color));
_format_stack.add(format);
output.setSpan(format, length, length, Spanned.SPAN_MARK_MARK);
} else {
applySpan(output, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
private Object getLast(Editable text, Class kind) {
@SuppressWarnings("unchecked")
final Object[] spans = text.getSpans(0, text.length(), kind);
if (spans.length != 0)
for (int i = spans.length; i > 0; i--)
if (text.getSpanFlags(spans[i-1]) == Spannable.SPAN_MARK_MARK)
return spans[i-1];
return null;
}
private void applySpan(Editable output, int length, int flags) {
if (_format_stack.isEmpty()) return;
final Object format = _format_stack.remove(0);
final Object span = getLast(output, format.getClass());
final int where = output.getSpanStart(span);
output.removeSpan(span);
if (where != length)
output.setSpan(format, where, length, flags);
}
}));
Run Code Online (Sandbox Code Playgroud)
这似乎确实获得了项目符号、前景色和背景色。它可能适用于字体,但您可能需要提供字体,因为 Android 似乎不支持 Droid/Roboto 以外的字体。
这更像是一个概念验证,您可能希望将正则表达式转换为String处理,因为正则表达式不支持以任何方式组合预处理,这意味着这需要在String. 这似乎也没有改变字体大小,我尝试将其定义为“16sp”、“中等”或“4”而没有看到任何变化。如果有人有尺寸可以工作,介意分享吗?
我目前希望能够为此添加编号/有序列表支持,即
注意:
对于以任何这样的方式开始的人来说,似乎给出的“标签”handleTag(...)只是标签的名称(如“span”),并且不包含在标签中分配的任何属性(如如果你有"),你可以看到我围绕这个背景颜色的漏洞。
| 归档时间: |
|
| 查看次数: |
24237 次 |
| 最近记录: |