android textView设置html,解决图片和文字不对齐的问题

evernote中的笔记,这里分享一下:

evernote笔记入口


用textview可以显示html富文本,比显示单纯的文字要友好很多,效果图:

android textView设置html,解决图片和文字不对齐的问题_第1张图片
     

但是问题也很多。
首先是 html 的支持实在有限,很多在html中比较easy的事情,在这里就感觉很困难,项目中遇到的两个问题:
     1. 调整字体大小的时候,图片不随着变化,显得不协调
     2. 调整textview行间距的时候,文字间间距是变大了,并且文字居上,但是图片居下,导致文字和图片错开。
由于无法通过html的方式来解决,只能去看android是否提供了相关方法了,结果并没有方法能够直接支持这样的需要,只好想办法了。

问题1解决:

观察方法时发现:
         
 Html.fromHtml(html, new ImageGetter() {...}, null);  

这里有个ImageGetter,这里有个:
          drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());  
大概意思是按照drawable的宽高来设置边界,考虑调整这里,将边界*2会是神马效果。运行之后发现,图标变大了一倍,那么问题1就有办法了,只要将这里的图片大小和字体大小对应上就可以,在字体大小调整的时候,通知到这里就行。 这里的图片是根据字体大小16sp来做的,所以得到当前字体大小,按比例放大图标应该就可以。
     drawable.setBounds(0, 0,
          (int)(drawable.getIntrinsicWidth()*(cFontSize/16.0)),
          (int)(drawable.getIntrinsicHeight()*(cFontSize/16.0)));


 
最后代码为:
Spanned spanned = Html.fromHtml(content, new ImageGetter(){
     @Override 
    public Drawable getDrawable(String source) { 
        Drawable drawable = getResources().getDrawable( 
                getResourceId(source)); 
       
          drawable.setBounds(0, 0,
          (int)(drawable.getIntrinsicWidth()*(cFontSize/16.0)),
          (int)(drawable.getIntrinsicHeight()*(cFontSize/16.0)));
        return drawable; 
    }
}, null);


问题2解决:


     这里解决的时候,参考了网上的资料, http://stackoverflow.com/questions/3253148/imagespan-is-cut-off-incorrectly-aligned
主要是重写了ImageSpan,因为ImageSpan只有两个:ImageSpan.ALIGN_BASELINE 和 ImageSpan.ALIGN_BOTTOM ,这两个都不能满足和文字平行的需要。
首先是普通处理的代码。
    
 Spanned spanned = Html.fromHtml(content, new ImageGetter() {...} , null);
     if (spanned instanceof SpannableStringBuilder) {
            ImageSpan[] imageSpans = spanned.getSpans(0, spanned.length(), ImageSpan.class);
            for (ImageSpan imageSpan : imageSpans) {
                int start = spanned.getSpanStart(imageSpan);
                int end = spanned.getSpanEnd(imageSpan);
                Drawable d = imageSpan.getDrawable();
                ImageSpan newImageSpan = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
                ((SpannableStringBuilder) spanned).setSpan(newImageSpan, start, end, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
                ((SpannableStringBuilder) spanned).removeSpan(imageSpan);
            }
     }

这里从html中得到所有的ImageSpan,并设置好对应的属性,将新的span加入进去,并移除旧的。思路就在将新的span换成符合自己要求的span。
@Override
public void draw(Canvas canvas, CharSequence text,
                 int start, int end, float x,
                 int top, int y, int bottom, Paint paint) {
    Drawable b = mDrawable;
    canvas.save();

    int transY = bottom - b.getBounds().bottom;
    if (mVerticalAlignment == ALIGN_BASELINE) {
        int textLength = text.length();
        for (int i = 0; i < textLength; i++) {
            if (Character.isLetterOrDigit(text.charAt(i))) {
                transY -= paint.getFontMetricsInt().descent;
                break;
            }
        }
    }

    canvas.translate(x, transY);
    b.draw(canvas);
    canvas.restore();
}


说实话,这里面都干得啥,老外没写注释,图片处理也不熟,只能自己来试了。translate是偏移的意思,就拿他开刀,给transY一个值,运行之后发现,图片真的Y方向偏移了,问题2也就有办法了。得到textView设置的行间距,从dip转换为px,用transY减掉,那么图片就会相应的向上偏移行间距的长度,也就和文字平行了。调整之后的类:
public class StickerSpan extends ImageSpan {

    public StickerSpan(Drawable b, int verticalAlignment) {
        super(b, verticalAlignment);

    }

    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x,
                     int top, int y, int bottom, Paint paint) {
        Drawable b = getDrawable();
        canvas.save();
        int transY = bottom - b.getBounds().bottom - Utils.dip2px(WApplication.cFontLineSpacingExtra);
        if (mVerticalAlignment == ALIGN_BASELINE) {
            int textLength = text.length();
            for (int i = 0; i < textLength; i++) {
                if (Character.isLetterOrDigit(text.charAt(i))) {
                    transY -= paint.getFontMetricsInt().descent;
                    break;
                }
            }
        }
        canvas.translate(x, transY);
        b.draw(canvas);
        canvas.restore();
    }
}



然后将 ImageSpan newImageSpan = new ImageSpan(...); 
修改为 StickerSpan StickerSpan =  new StickerSpan(…);

对比一下最后的效果图:
     

你可能感兴趣的:(html,android)