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

本文介绍在Android中实现图文环绕效果的方法,包括使用TextView的ImageSpan和自定义View实现。通过实例展示了如何创建自定义View来模拟CSS中的float浮动效果,实现更灵活的图文布局。
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实现图文环绕

 

package com.example.appviewdemo;

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 MyImageText 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 MyImageText(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         init();
     }
 
    public MyImageText(Context context, AttributeSet attrs) {
         super(context, attrs);
         init();
     }
 
    public MyImageText(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 + "]";
         }
     }
 }

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

 




                
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值