Android TextView에서 HTML 목록 태그가 작동하지 않습니다. 어떡해?
Android TextView에서 HTML 목록 태그가 작동하지 않습니다. 이것은 내 문자열 내용입니다.
String str="A dressy take on classic gingham in a soft, textured weave of stripes that resembles twill. Take a closer look at this one.<ul><li>Trim, tailored fit for a bespoke feel</li><li>Medium spread collar, one-button mitered barrel cuffs</li><li>Applied placket with genuine mother-of-pearl buttons</li><li>;Split back yoke, rear side pleats</li><li>Made in the U.S.A. of 100% imported cotton.</li></ul>";
다음과 같은 텍스트보기로로드했습니다.
textview.setText(Html.fromHtml(str));
출력은 단락처럼 보입니다. 어떡해? 그것에 대한 해결책이 있습니까?
편집하다:
webview.loadData(str,"text/html","utf-8");
당신은에서 볼 수 있듯이 Html
클래스의 소스 코드 , Html.fromHtml(String)
모든 HTML 태그를 지원하지 않습니다. 바로이 경우에, <ul>
그리고 <li>
지원되지 않습니다.
소스 코드에서 허용 된 HTML 태그 목록을 작성했습니다.
br
p
div
em
b
strong
cite
dfn
i
big
small
font
blockquote
tt
monospace
a
u
sup
sub
그래서 당신은 더 나은 사용 WebView
과 그 loadDataWithBaseURL
방법. 다음과 같이 시도하십시오.
String str="<html><body>A dressy take on classic gingham in a soft, textured weave of stripes that resembles twill. Take a closer look at this one.<ul><li>Trim, tailored fit for a bespoke feel</li><li>Medium spread collar, one-button mitered barrel cuffs</li><li>Applied placket with genuine mother-of-pearl buttons</li><li>;Split back yoke, rear side pleats</li><li>Made in the U.S.A. of 100% imported cotton.</li></ul></body></html>";
webView.loadDataWithBaseURL(null, str, "text/html", "utf-8", null);
오래된 질문처럼 보입니다. 같은 문제가 있습니다. 내가 한 일은 기본 TagHandler를 재정의하는 것입니다 . 저는 StackOverflow 및 Android를 처음 사용하며 수정이나 더 나은 방법에 감사드립니다. :) 이것은 나를 위해 일했습니다.
package com.tumblr.amangautam.cars;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.Html.TagHandler;
import android.util.Log;
public class MyTagHandler implements TagHandler{
boolean first= true;
String parent=null;
int index=1;
@Override
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if(tag.equals("ul")) parent="ul";
else if(tag.equals("ol")) parent="ol";
if(tag.equals("li")){
if(parent.equals("ul")){
if(first){
output.append("\n\t•");
first= false;
}else{
first = true;
}
}
else{
if(first){
output.append("\n\t"+index+". ");
first= false;
index++;
}else{
first = true;
}
}
}
}
}
텍스트를 표시하기 위해 ...
myTextView.setText(Html.fromHtml("<ul><li>I am an Android developer</li><li>Another Item</li></ul>", null, new MyTagHandler()));
[편집하다]
Kuitsi는 또한 동일한 작업을 수행 하는 정말 좋은 라이브러리 를 게시했습니다 .
이 SO 링크 에서 얻었습니다 .
전체 샘플 프로젝트는 https://bitbucket.org/Kuitsi/android-textview-html-list에 있습니다.
샘플 사진은 https://kuitsi.bitbucket.io/stackoverflow3150400_screen.png 에서 제공됩니다.
이 솔루션은 masha의 대답에 가장 가깝습니다 . 일부 코드는 내부 클래스에서도 가져옵니다 android.text.Html.HtmlToSpannedConverter
. 중첩 된 정렬 된 목록과 정렬되지 않은 목록을 지원하지만 정렬 된 목록의 너무 긴 텍스트는 여전히 텍스트가 아닌 항목 번호와 정렬됩니다. 혼합 목록 (ol 및 ul)도 약간의 작업이 필요합니다. 샘플 프로젝트의 구현을 포함 Html.TagHandler 에 전달됩니다 Html.fromHtml (문자열, ImageGetter, TagHandler을) .
편집 : 더 넓은 HTML 태그 지원을 위해 https://github.com/NightWhistler/HtmlSpanner 도 시도해 볼 가치가 있습니다.
Aman Guatam 코드에 대한 작은 수정. 위의 함수는 개행 문자를 렌더링하는 문제가 있습니다. 예 : before <li>
태그가 <p>
태그 인 경우 2 개의 개행 문자가 렌더링됩니다. 다음은 업그레이드 된 코드입니다.
import org.xml.sax.XMLReader;
import android.text.Editable;
import android.text.Html.TagHandler;
public class ListTagHandler implements TagHandler {
boolean first = true;
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
// TODO Auto-generated method stub
if (tag.equals("li")) {
char lastChar = 0;
if (output.length() > 0)
lastChar = output.charAt(output.length() - 1);
if (first) {
if (lastChar == '\n')
output.append("\t• ");
else
output.append("\n\t• ");
first = false;
} else {
first = true;
}
}
}
}
경고
2016 년 2 월 10 일부터 android.text.Html
실제로 기본을 지원 li
하고 ul
태그를 지정하고 사용합니다. new BulletSpan()
즉, 최신 버전의 Android에서는 Html.TagHandler
여기에 게시 된 솔루션이 무시됩니다.
BulletSpan이 기본값보다 더 큰 간격으로 예상되는 경우 코드가이 변경 사항을 처리하는지 확인하십시오. 범위를 찾고 / 바꾸는 일종의 솔루션이 있어야합니다.
LeadingMarginSpan을 사용하는 다른 솔루션. 정렬 된 목록과 정렬되지 않은 목록 및 중첩을 처리합니다.
public class ListTagHandler implements TagHandler
{
private int m_index = 0;
private List< String > m_parents = new ArrayList< String >( );
@Override
public void handleTag( final boolean opening, final String tag, Editable output, final XMLReader xmlReader )
{
if( tag.equals( "ul" ) || tag.equals( "ol" ) || tag.equals( "dd" ) )
{
if( opening )
{
m_parents.add( tag );
}
else m_parents.remove( tag );
m_index = 0;
}
else if( tag.equals( "li" ) && !opening ) handleListTag( output );
}
private void handleListTag( Editable output )
{
if( m_parents.get(m_parents.size()-1 ).equals( "ul" ) )
{
output.append( "\n" );
String[ ] split = output.toString( ).split( "\n" );
int lastIndex = split.length - 1;
int start = output.length( ) - split[ lastIndex ].length( ) - 1;
output.setSpan( new BulletSpan( 15 * m_parents.size( ) ), start, output.length( ), 0 );
}
else if( m_parents.get(m_parents.size()-1).equals( "ol" ) )
{
m_index++ ;
output.append( "\n" );
String[ ] split = output.toString( ).split( "\n" );
int lastIndex = split.length - 1;
int start = output.length( ) - split[ lastIndex ].length( ) - 1;
output.insert( start, m_index + ". " );
output.setSpan( new LeadingMarginSpan.Standard( 15 * m_parents.size( ) ), start, output.length( ), 0 );
}
}
}
목록의 형식 만 지정해야하는 경우 단순하게 유지하고 동일한 결과를 얻으려면 TextView에 유니 코드 문자를 복사 / 붙여 넣기하십시오.
• 유니 코드 문자 'BULLET'(U + 2022)
TagHandler 구현을 찾고 여기에 왔습니다. 모두의 Truong 구엔과 아만 Guatam 대답은 아주 좋은,하지만 난 둘의 혼합 버전을 필요 : 내가하지 그것을 overformat 내 솔루션을 필요로하고 ressolve 할 수 있도록 <ol>
내가 좋아하는 뭔가를 구문 분석하고 있습니다 때문에, 태그를 <h3>title</h3><ol><li>item</li><li>item</li><li>item</li></ol>
.
여기 내 해결책이 있습니다.
import org.xml.sax.XMLReader;
import android.text.Editable;
import android.text.Html.TagHandler;
public class MyTagHandler implements TagHandler {
boolean first = true;
String parent = null;
int index = 1;
public void handleTag(final boolean opening, final String tag,
final Editable output, final XMLReader xmlReader) {
if (tag.equals("ul")) {
parent = "ul";
index = 1;
} else if (tag.equals("ol")) {
parent = "ol";
index = 1;
}
if (tag.equals("li")) {
char lastChar = 0;
if (output.length() > 0) {
lastChar = output.charAt(output.length() - 1);
}
if (parent.equals("ul")) {
if (first) {
if (lastChar == '\n') {
output.append("\t• ");
} else {
output.append("\n\t• ");
}
first = false;
} else {
first = true;
}
} else {
if (first) {
if (lastChar == '\n') {
output.append("\t" + index + ". ");
} else {
output.append("\n\t" + index + ". ");
}
first = false;
index++;
} else {
first = true;
}
}
}
}
}
새 목록이 시작될 때마다 색인 값을 재설정하므로 다음과 같이 목록을 중첩하면 작동하지 않습니다. <ol><li>1<ol><li>1.1</li><li>1.2</li></ol><li>2</li></ol>
- 1
- 1.1
- 1.2
- 2
그 코드로, 당신은 얻을 것 1, 1, 2, 3
대신에 1, 1, 2, 2
.
물론 Android TextView에 글 머리 기호를 표시하는 방법이 있습니다. <li>
태그를 •
(글 머리 기호의 HTML 코드)로 바꿀 수 있습니다 .
다른 목록 아이콘을 사용하려면이 링크를 표에서 선호하는 아이콘을 사용하십시오.
"li"를 유니 코드로 간단히 바꿀 수 있습니다.
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
if (tag.equalsIgnoreCase("li")) {
if (opening) {
output.append("\u2022 ");
} else {
output.append("\n");
}
}
}
Voldermort 경의 대답 은 좋은 출발점입니다. 그러나 글 머리 기호 대신 ol
정렬 된 목록을 표시 하려면 태그가 필요했습니다 1. 2. 3. ....
. 또한 중첩 태그가 제대로 작동하려면 특별한 처리가 필요합니다.
내 코드에서, 나는 개폐를 추적 유지하기 위해 스택 (parentList)를 유지하고있다 ul
및 ol
태그 또한 현재 열려있는 태그를 알고. 또한 levelWiseCounter
중첩 된 ol
태그의 경우 다른 개수를 유지 하는 데 사용됩니다 .
myTextView.setText(Html.fromHtml("your string", null, new CustomTagHandler()));
. . .
private static class CustomTagHandler implements TagHandler
{
int level = 0;
private LinkedList<Tag> parentList = new LinkedList<DetailFragment.CustomTagHandler.Tag>();
private HashMap<Integer, Integer> levelWiseCounter = new HashMap<Integer, Integer>();
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader)
{
if (tag.equalsIgnoreCase("ul") || tag.equalsIgnoreCase("ol"))
{
if (opening)
{
if (tag.equalsIgnoreCase("ul"))
{
parentList.push(Tag.UL);
}
else
{
parentList.push(Tag.OL);
}
level++;
}
else
{
if (!parentList.isEmpty())
{
parentList.pop();
//remove counter at that level, in any present.
levelWiseCounter.remove(level);
}
level--;
if (level < 0)
{
level = 0;
}
}
}
else if (tag.equalsIgnoreCase("li"))
{
if (opening && level > 0)
{
//new line check
int length = output.toString().length();
if (length > 0 && (output.toString().charAt(length - 1) == '\n'))
{
}
else
{
output.append("\n");
}
//add tabs as per current level of li
for (int i = 0; i < level; i++)
{
output.append("\t");
}
// append dot or numbers based on parent tag
if (Tag.UL == parentList.peek())
{
output.append("•");
}
else
{
//parent is OL. Check current level and retreive counter from levelWiseCounter
int counter = 1;
if (levelWiseCounter.get(level) == null)
{
levelWiseCounter.put(level, 1);
}
else
{
counter = levelWiseCounter.get(level) + 1;
levelWiseCounter.put(level, counter);
}
output.append(padInt(counter) + ".");
}
//trailing tab
output.append("\t");
}
}
}
/**
* Add padding so that all numbers are aligned properly. Currently supports padding from 1-99.
*
* @param num
* @return
*/
private static String padInt(int num)
{
if (num < 10)
{
return " " + num;
}
return "" + num;
}
private enum Tag
{
UL, OL
}
}
다음 코드는 어떻습니까 ( 이 링크 기반 ) :
public class TextViewHtmlTagHandler implements TagHandler
{
/**
* Keeps track of lists (ol, ul). On bottom of Stack is the outermost list
* and on top of Stack is the most nested list
*/
Stack<String> lists =new Stack<String>();
/**
* Tracks indexes of ordered lists so that after a nested list ends
* we can continue with correct index of outer list
*/
Stack<Integer> olNextIndex =new Stack<Integer>();
/**
* List indentation in pixels. Nested lists use multiple of this.
*/
private static final int indent =10;
private static final int listItemIndent =indent*2;
private static final BulletSpan bullet =new BulletSpan(indent);
@Override
public void handleTag(final boolean opening,final String tag,final Editable output,final XMLReader xmlReader)
{
if(tag.equalsIgnoreCase("ul"))
{
if(opening)
lists.push(tag);
else lists.pop();
}
else if(tag.equalsIgnoreCase("ol"))
{
if(opening)
{
lists.push(tag);
olNextIndex.push(Integer.valueOf(1)).toString();// TODO: add support for lists starting other index than 1
}
else
{
lists.pop();
olNextIndex.pop().toString();
}
}
else if(tag.equalsIgnoreCase("li"))
{
if(opening)
{
if(output.length()>0&&output.charAt(output.length()-1)!='\n')
output.append("\n");
final String parentList=lists.peek();
if(parentList.equalsIgnoreCase("ol"))
{
start(output,new Ol());
output.append(olNextIndex.peek().toString()+". ");
olNextIndex.push(Integer.valueOf(olNextIndex.pop().intValue()+1));
}
else if(parentList.equalsIgnoreCase("ul"))
start(output,new Ul());
}
else if(lists.peek().equalsIgnoreCase("ul"))
{
if(output.charAt(output.length()-1)!='\n')
output.append("\n");
// Nested BulletSpans increases distance between bullet and text, so we must prevent it.
int bulletMargin=indent;
if(lists.size()>1)
{
bulletMargin=indent-bullet.getLeadingMargin(true);
if(lists.size()>2)
// This get's more complicated when we add a LeadingMarginSpan into the same line:
// we have also counter it's effect to BulletSpan
bulletMargin-=(lists.size()-2)*listItemIndent;
}
final BulletSpan newBullet=new BulletSpan(bulletMargin);
end(output,Ul.class,new LeadingMarginSpan.Standard(listItemIndent*(lists.size()-1)),newBullet);
}
else if(lists.peek().equalsIgnoreCase("ol"))
{
if(output.charAt(output.length()-1)!='\n')
output.append("\n");
int numberMargin=listItemIndent*(lists.size()-1);
if(lists.size()>2)
// Same as in ordered lists: counter the effect of nested Spans
numberMargin-=(lists.size()-2)*listItemIndent;
end(output,Ol.class,new LeadingMarginSpan.Standard(numberMargin));
}
}
else if(opening)
Log.d("TagHandler","Found an unsupported tag "+tag);
}
private static void start(final Editable text,final Object mark)
{
final int len=text.length();
text.setSpan(mark,len,len,Spanned.SPAN_MARK_MARK);
}
private static void end(final Editable text,final Class<?> kind,final Object... replaces)
{
final int len=text.length();
final Object obj=getLast(text,kind);
final int where=text.getSpanStart(obj);
text.removeSpan(obj);
if(where!=len)
for(final Object replace : replaces)
text.setSpan(replace,where,len,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return;
}
private static Object getLast(final Spanned text,final Class<?> kind)
{
/*
* This knows that the last returned object from getSpans()
* will be the most recently added.
*/
final Object[] objs=text.getSpans(0,text.length(),kind);
if(objs.length==0)
return null;
return objs[objs.length-1];
}
private static class Ul
{
}
private static class Ol
{
}
}
@Kuitsis 솔루션으로 목록 뒤에 항상 빈 줄이 있다는 문제가있었습니다. handleTag ()에 몇 줄을 추가했고 이제 빈 줄이 사라졌습니다.
@Override
public void handleTag(final boolean opening, final String tag, final Editable output, final XMLReader xmlReader) {
if (UL_TAG.equalsIgnoreCase(tag)) {
if (opening) { // handle <ul>
lists.push(new Ul());
} else { // handle </ul>
lists.pop();
if (output.length() > 0 && output.charAt(output.length() - 1) == '\n') {
output.delete(output.length() - 1, output.length());
}
}
} else if (OL_TAG.equalsIgnoreCase(tag)) {
if (opening) { // handle <ol>
lists.push(new Ol()); // use default start index of 1
} else { // handle </ol>
lists.pop();
if (output.length() > 0 && output.charAt(output.length() - 1) == '\n') {
output.delete(output.length() - 1, output.length());
}
}
} else if (LI_TAG.equalsIgnoreCase(tag)) {
if (opening) { // handle <li>
lists.peek().openItem(output);
} else { // handle </li>
lists.peek().closeItem(output, lists.size());
}
} else {
Log.d("TagHandler", "Found an unsupported tag " + tag);
}
}
사용할 수 있습니다 Html.TagHandler
. 아래는 kotlin에 사용할 수 있습니다.
class UlTagHandler : Html.TagHandler {
override fun handleTag(
opening: Boolean, tag: String, output: Editable,
xmlReader: XMLReader
) {
if (tag == "ul" && !opening) output.append("\n")
if (tag == "li" && opening) output.append("\n\t•")
}
}
과
textView.setText(Html.fromHtml(myHtmlText, null, UlTagHandler()));
이것은 kassim이 말한 것에 대한 확인입니다. 조각화가 있습니다. 이 문제를 해결하는 방법을 찾았습니다. <li>
사용자 정의 태그 로 이름을 바꾸고 ul을해야합니다. 그래서:
myHTML.replaceAll("</ul>","</customTag>").replaceAll("<ul>","<customTag>");
//likewise for li
그런 다음 내 처리기에서 해당 customTag (아무것도하지 않음)를 찾고 무언가를 할 수 있습니다.
//now my handler can handle the customtags. it was ignoring them after nougat.
public class UlTagHandler implements Html.TagHandler {
//for ul in nougat and up this tagHandler is completely ignored
@Override
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if (tag.equals("customtag2") && opening)
output.append("\n\t\u25CF\t");
if (tag.equals("customtag2") && !opening)
output.append("\n");
}
}
이것은 모든 버전의 안드로이드에서 작동합니다.
'Programming' 카테고리의 다른 글
소수점 이하 숫자를 얻는 방법? (0) | 2020.08.25 |
---|---|
Red Hat Linux에서 표준 도구를 사용하여 파일의 행을 무작위 화하려면 어떻게해야합니까? (0) | 2020.08.25 |
세 번째 변수를 사용하지 않고 두 변수 값 바꾸기셸에서 가비지 수집을 어떻게 강제합니까? (0) | 2020.08.25 |
텍스트를 변경할 때마다 UITextView를 맨 위로 스크롤하려면 어떻게해야합니까? (0) | 2020.08.25 |
Java에서 String []을 쉼표로 구분 된 문자열로 변환 (0) | 2020.08.25 |