Android自定义View实现HTML图文环绕效果

Android中并没有提供HTML图文环绕效果的View,最接近的算是TextView中的ImageSpan了,但并未完全实现图文环绕(图文混排)的效果。

1、Android系统TextView的ImageSpan实现图文环绕

 

代码如下:
TextView tv = new TextView ( this ) ;
       
SpannableString spanStr = new SpannableString ( "掌声那历史的房间里是副经理撒旦法阿斯顿及福利费是到发顺丰" ) ;
ImageSpan imageSpan = new ImageSpan ( this, R. drawable. a ) ;
spanStr. setSpan (imageSpan, 3, 5, Spannable. SPAN_INCLUSIVE_INCLUSIVE ) ;
tv. setText (spanStr ) ;
       
setContentView (tv ) ;

2、Android中自定义View实现图文环绕

代码如下:

FloatImageText view = new FloatImageText ( this ) ;
view. setText ( "电视里发生了房间里是积分拉萨积分拉萨积分拉萨减肥啦空间  撒旦法发大水发撒旦法看完了鸡肉味容积率为热键礼物i经二路文件容量为积分拉萨解放路口上飞机撒离开房间爱水立方法拉圣诞节福禄寿" ) ;
Bitmap bm = BitmapFactory. decodeResource (getResources ( ), R. drawable. a ) ;
view. setImageBitmap (bm, 30, 30 ) ;

 

 

package com.orgcent.view ;

import java.util.ArrayList ;

import android.content.Context ;
import android.graphics.Bitmap ;
import android.graphics.Canvas ;
import android.graphics.Color ;
import android.graphics.Paint ;
import android.graphics.Rect ;
import android.graphics.Paint.FontMetrics ;
import android.util.AttributeSet ;
import android.util.DisplayMetrics ;
import android.view.View ;
/**
* 模拟CSS中的float浮动效果
*/
public class FloatImageText extends View {
    private Bitmap mBitmap ;
    private final Rect bitmapFrame = new Rect ( ) ;
    private final Rect tmp = new Rect ( ) ;
    private int mTargetDentity = DisplayMetrics. DENSITY_DEFAULT ;
   
    private final Paint mPaint = new Paint ( Paint. ANTI_ALIAS_FLAG ) ;
    private String mText ;
    private ArrayList <TextLine > mTextLines ;
    private final int [ ] textSize = new int [ 2 ] ;

    public FloatImageText ( Context context, AttributeSet attrs, int defStyle ) {
        super (context, attrs, defStyle ) ;
        init ( ) ;
    }

    public FloatImageText ( Context context, AttributeSet attrs ) {
        super (context, attrs ) ;
        init ( ) ;
    }

    public FloatImageText ( Context context ) {
        super (context ) ;
        init ( ) ;
    }
   
    private void init ( ) {
        mTargetDentity = getResources ( ). getDisplayMetrics ( ). densityDpi ;
        mTextLines = new ArrayList <TextLine > ( ) ;
       
        mPaint. setTextSize ( 14 ) ;
        mPaint. setColor ( Color. RED ) ;
       
    }
   
   

    @Override
    protected void onMeasure ( int widthMeasureSpec, int heightMeasureSpec ) {
        int w = 0, h = 0 ;
        //图片大小
        w += bitmapFrame. width ( ) ;
        h += bitmapFrame. height ( ) ;
       
        //文本宽度
        if ( null != mText && mText. length ( ) > 0 ) {
            mTextLines. clear ( ) ;
            int size = resolveSize ( Integer. MAX_VALUE, widthMeasureSpec ) ;
            measureAndSplitText (mPaint, mText, size ) ;
            final int textWidth = textSize [ 0 ], textHeight = textSize [ 1 ] ;
            w += textWidth ; //内容宽度
            if (h < textHeight ) { //内容高度
                h = ( int ) textHeight ;
            }
        }
       
        w = Math. max (w, getSuggestedMinimumWidth ( ) ) ;
        h = Math. max (h, getSuggestedMinimumHeight ( ) ) ;
       
        setMeasuredDimension (
                resolveSize (w, widthMeasureSpec ),
                resolveSize (h, heightMeasureSpec ) ) ;
    }
   
    @Override
    protected void onDraw ( Canvas canvas ) {
        //绘制图片
        if ( null != mBitmap ) {
            canvas. drawBitmap (mBitmap, null, bitmapFrame, null ) ;
        }
       
        //绘制文本
        TextLine line ;
        final int size = mTextLines. size ( ) ;
        for ( int i = 0 ; i < size ; i ++ ) {
            line = mTextLines. get (i ) ;
            canvas. drawText (line. text, line. x, line. y, mPaint ) ;
        }
        System. out. println (mTextLines ) ;
    }
   
   
    public void setImageBitmap (Bitmap bm ) {
        setImageBitmap (bm, null ) ;
    }
   
    public void setImageBitmap (Bitmap bm, int left, int top ) {
        setImageBitmap (bm, new Rect (left, top, 0, 0 ) ) ;
    }
   
    public void setImageBitmap (Bitmap bm, Rect bitmapFrame ) {
        mBitmap = bm ;
        computeBitmapSize (bitmapFrame ) ;
        requestLayout ( ) ;
        invalidate ( ) ;
    }
   
    public void setText ( String text ) {
        mText = text ;
        requestLayout ( ) ;
        invalidate ( ) ;
    }
   
    private void computeBitmapSize (Rect rect ) {
        if ( null != rect ) {
            bitmapFrame. set (rect ) ;
        }
        if ( null != mBitmap ) {
            if (rect. right == 0 && rect. bottom == 0 ) {
                final Rect r = bitmapFrame ;
                r. set (r. left, r. top,
                        r. left + mBitmap. getScaledHeight (mTargetDentity ),
                        r. top + mBitmap. getScaledHeight (mTargetDentity ) ) ;
            }
        } else {
             bitmapFrame. setEmpty ( ) ;
        }
    }
   
    private void measureAndSplitText ( Paint p, String content, int maxWidth ) {
        FontMetrics fm = mPaint. getFontMetrics ( ) ;
        final int lineHeight = ( int ) (fm. bottom - fm. top ) ;
       
        final Rect r = new Rect (bitmapFrame ) ;
//        r.inset(-5, -5);
       
        final int length = content. length ( ) ;
        int start = 0, end = 0, offsetX = 0, offsetY = 0 ;
        int availWidth = maxWidth ;
        TextLine line ;
        boolean onFirst = true ;
        boolean newLine = true ;
        while (start < length ) {
            end ++;
            if (end == length ) { //剩余的不足一行的文本
                if (start <= length - 1 ) {
                    if (newLine ) offsetY += lineHeight ;
                    line = new TextLine ( ) ;
                    line. text = content. substring (start, end - 1 ) ;
                    line. x = offsetX ;
                    line. y = offsetY ;
                    mTextLines. add (line ) ;
                }
                break ;
            }
            p. getTextBounds (content, start, end, tmp ) ;
            if (onFirst ) { //确定每个字符串的坐标
                onFirst = false ;
                final int height = lineHeight + offsetY ;
                if (r. top >= height ) { //顶部可以放下一行文字
                    offsetX = 0 ;
                    availWidth = maxWidth ;
                    newLine = true ;
                } else if (newLine && (r. bottom >= height && r. left >= tmp. width ( ) ) ) { //中部左边可以放文字
                    offsetX = 0 ;
                    availWidth = r. left ;
                    newLine = false ;
                } else if (r. bottom >= height && maxWidth - r. right >= tmp. width ( ) ) { //中部右边
                    offsetX = r. right ;
                    availWidth = maxWidth - r. right ;
                    newLine = true ;
                } else { //底部
                    offsetX = 0 ;
                    availWidth = maxWidth ;
                    if (offsetY < r. bottom ) offsetY = r. bottom ;
                    newLine = true ;
                }
            }
           
            if (tmp. width ( ) > availWidth ) { //保存一行能放置的最大字符串
                onFirst = true ;
                line = new TextLine ( ) ;
                line. text = content. substring (start, end - 1 ) ;
                line. x = offsetX ;
                mTextLines. add (line ) ;
                if (newLine ) {
                    offsetY += lineHeight ;
                    line. y = offsetY ;
                } else {
                    line. y = offsetY + lineHeight ;
                }
               
                start = end - 1 ;
            }
        }
        textSize [ 1 ] = offsetY ;
    }
   
    class TextLine {
        String text ;
        int x ;
        int y ;
       
        @Override
        public String toString ( ) {
            return "TextLine [text=" + text + ", x=" + x + ", y=" + y + "]" ;
        }
    }
}

 

 

转载于:https://my.oschina.net/u/573470/blog/92434

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值