2016-02-26 21 views
1

我有一些HTML內容的東西,如如何在android單個Textview上顯示html內容文本之間的水平線?

<html> 
<h3>nested unordered lists</h3> 
<ul> 
    <li> 
    first level 
    <ul> 
     <li> 
      second level 
      <ul> 
       <li> 
       third level 
       <ul> 
        <li> 
         fourth level 
         <ul> 
          <li>fifth level</li> 
         </ul> 
        </li> 
        <li>fourth level</li> 
       </ul> 
       </li> 
       <li>third level</li> 
      </ul> 
     </li> 
     <li>second level</li> 
     <li>second level: this should be a long enough text that will be wrapped into multiple lines</li> 
    </ul> 
    </li> 
    <li>first level</li> 
</ul> 

<hr> 
<h3>nested ordered lists</h3> 
<ol> 
    <li> 
    first level 
    <ol> 
     <li> 
      second level 
      <ol> 
       <li> 
       third level 
       <ol> 
        <li> 
         fourth level 
         <ol> 
          <li>fifth level</li> 
         </ol> 
        </li> 
        <li>fourth level</li> 
       </ol> 
       </li> 
       <li>third level</li> 
      </ol> 
     </li> 
     <li>second level</li> 
     <li>second level: this should be a long enough text that will be wrapped into multiple lines</li> 
    </ol> 
    </li> 
    <li>first level</li> 
</ol> 

<hr> 
<h3>Mixed (ol and ul) nested lists:</h3> 
<ul> 
    <li> 
    first unordered 
    <ol> 
     <li>first ordered</li> 
     <li> 
      second ordered 
      <ul> 
       <li> 
       unordered in second ordered 
       <ol> 
        <li>ordered in "unordered in second ordered"</li> 
        <li>another ordered in ""unordered in second ordered"</li> 
       </ol> 
       </li> 
      </ul> 
     </li> 
     <li>third ordered with some other formatting: <b>bold</b> and <i>italics</i></li> 
    </ol> 
    </li> 
    <li>second unordered</li> 
</ul> 
</html> 

現在我想顯示在單TextView的HTML內容。下面

textView.setText(Html.fromHtml(htmlContent, null, htmlTagHandler)); 

這裏

  • htmlTagHandler代碼段中給出是HtmlTagHandler參考其用於支持<ul><ol><li>標籤。

HtmlTagHandler.java:

public class HtmlTagHandler implements Html.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(boolean opening, String tag, Editable output, 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"); 
      } 
      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.length() > 0 && 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; 
        } 
       } 
       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.length() > 0 && 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(Editable text, Object mark) { 
    int len = text.length(); 
    text.setSpan(mark, len, len, Spanned.SPAN_MARK_MARK); 
    } 

    private static void end(Editable text, Class<?> kind, Object... replaces) { 
    int len = text.length(); 
    Object obj = getLast(text, kind); 
    int where = text.getSpanStart(obj); 
    text.removeSpan(obj); 
    if (where != len) { 
     for (Object replace: replaces) { 
      text.setSpan(replace, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 
     } 
     } 
     return; 
    } 


    private static Object getLast(Spanned text, Class<?> 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; 
     } 
     return objs[objs.length - 1]; 
     } 

    private static class Ul { } 
    private static class Ol { } 
    } 

在這裏,我能夠通過使用Html.fromHtml(htmlContent,htmlImageGet,htmlTagHandler)而不是水平線顯示項目符號和編號。任何人都可以引導我如何顯示水平線或在Html.fromHtml()方法支持<hr>標記方法的幫助下HtmlTagHandler或其他任何方法。

預期的輸出如下圖所示。

enter image description here

一切正常預期水平線。任何人都可以幫助解決這個問題。

+1

不要使用一個TextView。如果你有這個複雜的HTML,使用WebView。 –

+0

在這裏,我們有內容編輯功能,如突出顯示文本,穿透,下劃線,繪畫等。這就是選擇Textview而不是webview的原因。 – sandeepmaaram

+0

TextView並不是真正意義上的。您應該使用自定義視圖,將其推向並超出其設計的範圍,並且如果您的數據支持模型是您使用html進行編碼的字符串,那麼您的效率會非常低下。但是,如果你絕對必須嘗試這樣做,你最好的選擇是自定義的spannable。 –

回答

2

這就是我已經解決了你的問題。這不是一個非常優雅的解決方案,但它的工作原理。

Html.TagHandler:

import org.xml.sax.XMLReader; 
import android.text.Editable; 
import android.text.Html; 
import android.text.Spannable; 
import android.text.Spanned; 
import android.util.Log; 

public class CustomTagHandler implements Html.TagHandler { 

    @Override 
    public void handleTag(final boolean opening, final String tag, 
          Editable output, final XMLReader xmlReader) { 
     if(tag.equals("hr")) { 
      handleHRTag(opening,output); 
     } 
    } 

    private void handleHRTag(boolean opening, Editable output) { 
     if(!opening) return; 
     int start = output.length(); 
     // The space is necessary, the block requires some content: 
     output.append(" \n"); 
     output.setSpan(new CustomHRSpan(0xff000000,5.0f,2.0f), 
         start, output.length(), 0); 
    } 
} 

然後創建一個CustomHRSpan類:

import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.RectF; 
import android.text.style.LineBackgroundSpan; 
import android.text.style.LineHeightSpan; 


public class CustomHRSpan implements LineBackgroundSpan, LineHeightSpan { 
    private final int color;   // Color of line 
    private final float height;  // Height of HR element 
    private final float line;   // Line size 
    private final float marginLeft; // Margin of line, left side 
    private final float marginRight; // Margin of line, right side 

    public CustomHRSpan(int color, float height, float line) { 
     this.color  = color; 
     this.height  = height; 
     this.line   = line; 
     this.marginLeft = 5.0f; 
     this.marginRight = 5.0f; 
    } 

    @Override 
    public void drawBackground(Canvas c, Paint p, int left, int right, int top, int baseline, int bottom, 
           CharSequence text, int start, int end, int lnum) { 
     int paintColor = p.getColor(); 
     float y = (float)(top+(bottom-top)/2) - line*0.5f; 
     RectF r = new RectF((float)left+marginLeft, y, 
          (float)(right-left)-marginRight, y+line); 
     p.setColor(color); 
     c.drawRect(r, p); 
     p.setColor(paintColor); 
    } 

    @Override 
    public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) { 
     fm.descent = (int)height/2; 
     fm.ascent = (int)height - fm.descent; 
     fm.leading = 0; 
     fm.top  = fm.ascent; 
     fm.bottom = fm.descent; 
    } 
} 
相關問題