文档章节

Android自定义View 实现图文混排

SuShine
 SuShine
发布于 2015/06/24 13:55
字数 740
阅读 44
收藏 0
package com.su.imagetextview;

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;


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(30);
		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 + "]";
		}
	}
}


package com.su.imagetextview;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Menu;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		FloatImageText view = new FloatImageText(this);

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

		setContentView(view);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);

		return true;
	}

}


本文转载自:http://blog.csdn.net/sfshine/article/details/8451653

共有 人打赏支持
SuShine
粉丝 123
博文 541
码字总数 153477
作品 0
朝阳
后端工程师
私信 提问
Android 解决图文混排,图片和文字居中对齐问题(ImageSpan)

一. 概述 众所周知,Android图文混排可以通过SpannableString来实现,通过在相应位置使用ImageSpan替换即可,但是使用过的人会发现,imageSpan只提供了两种对齐方式,如下所示: 但是在大多数...

Mr云台
2017/04/10
0
0
《IT蓝豹》listview实现各种版面设计功能

本项目主要listview实现各种版面设计功能,有实现列表的,gridview效果的,有混排效果的等等。 自定义TwoWayView继承RecyclerView,通过TwoWayView去根据布局实现到底选择哪一个效果, 本项目...

抉择很难
2015/11/11
0
0
同 android TextView 自动换行之后如果让每行的文本和图片都垂直居中,在这里我使用的textview显示html

院子里一哥们提问的问题 我遇到的相同的情况 同问 在TextView默认的情况下,显示的html如果是图文混排的时候是这种以底部对齐的,但是这样的效果不符合需求,但是看见猿题库这样的软件实现了...

chenyongrenren
2014/10/11
785
0
Android自定义View实现HTML图文环绕效果

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

带梦想一7飞
2012/11/28
0
0
Android中的File文件存储及读取file中的Bitmap

今年看了下android的文件存储,大致和java实现差不多 android提供了如下两个方法来打开本应用程序的数据文件的IO流: FileInputStream openFileInput(fileName); //输入流 FileOutputStream...

爱吃橙子的小石头
2014/12/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

深入解析ES6之数据解构的用法

本文介绍了深入理解ES6之数据解构的用法,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。 一 对象解构 对象解构语法在赋值语句的左...

前端攻城老湿
13分钟前
5
0
芯片原理和量子力学

很多文盲觉得量子力学只是一个数学游戏,没有应用价值,呵呵,下面咱给计算机芯片寻个祖宗,请看示范: 导体,咱能理解,绝缘体,咱也能理解,小盆友们第一次被物理整懵的,怕是半导体了,所...

天王盖地虎626
13分钟前
2
0
Django model update的各种用法介绍

Django model update的各种用法介绍 model update常规用法 假如我们的表结构是这样的: class User(models.Model): username=models.CharField(max_length=255,unique=True,verbose_na......

_Change_
17分钟前
1
0
Frost & Sullivan权威报告:阿里云再次领跑云WAF大中华区市场

近日,国际权威分析机构Frost & Sullivan 针对Web应用防火墙(简称“WAF”)领域发布了《2017年亚太区Web应用防火墙市场报告》,阿里云以市场占有率45.8%的绝对优势连续两年领跑大中华区云WAF...

阿里云官方博客
21分钟前
1
0
Java程序员可知为何公司宁花25K重新招人,也不花20K留住老员工?

身在职场,经常会暗自打听同事工资,尤其是得知身边新入职同事的工资居然比自己高,还高出一大截时,心里自然很不平衡,一心想要离职。 那么,为什么公司宁愿花高价招聘新员工也不愿意给老员...

Java填坑路
27分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部