ImageSpan类为TextView提供了图文混排的形式,在ImageSpan的构造函数中提供了一个参数 int verticalAlignment,表示垂直对齐方式,有两个参数 ALIGN_BASELINE、ALIGN_BOTTOM 分别为顶部、底部对齐,但是没有居中对齐的参数(其实会找到这篇文章的人应该知道这点了。。)
下面说说我的实现思路及方法
1.根据构造函数verticalAlignment参数找到影响对齐方式的代码
public ImageSpan(Context context, int resourceId, int verticalAlignment) {
super(verticalAlignment);
mContext = context;
mResourceId = resourceId;
}
2.查看DynamicDrawableSpan类源码找出对齐方式的代码,在源码中能看到两个方法getSize与draw
3.getSize方法,返回一个Int含义为图片的宽度,但是我们看源码发现里面干的事情不仅是返回宽度还设置了文字的ascent、descent的位置
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
Drawable d = getCachedDrawable();
Rect rect = d.getBounds();
if (fm != null) {
fm.ascent = -rect.bottom;
fm.descent = 0;
fm.top = fm.ascent;
fm.bottom = 0;
}
return rect.right;
}
4.draw方法,根据对齐参数绘制图片。所以第一步就是修改draw方法来实现居中
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
Drawable b = getCachedDrawable();
canvas.save();
int transY = bottom - b.getBounds().bottom;
if (mVerticalAlignment == ALIGN_BASELINE) {
transY -= paint.getFontMetricsInt().descent;
}
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
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 = 0;
//获得将要显示的文本高度-图片高度除2等居中位置+top(换行情况)
transY = ((bottom-top) - b.getBounds().bottom)/2+top;
//偏移画布后开始绘制
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
public int getSize(Paint paint, CharSequence text, int start, int end,
FontMetricsInt fm) {
Drawable d = getDrawable();
Rect rect = d.getBounds();
if (fm != null) {
FontMetricsInt fmPaint=paint.getFontMetricsInt();
//获得文字、图片高度
int fontHeight = fmPaint.bottom - fmPaint.top;
int drHeight=rect.bottom-rect.top;
//对于这段算法LZ表示也不解,正常逻辑应该同draw中的计算一样但是显示的结果不居中,经过几次调试之后才发现这么算才会居中
int top= drHeight/2 - fontHeight/4;
int bottom=drHeight/2 + fontHeight/4;
fm.ascent=-bottom;
fm.top=-bottom;
fm.bottom=top;
fm.descent=top;
}
return rect.right;
}
7.到这就完成了图文居中的功能,效果图
下面上完整源码,谢谢支持
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ImageSpan;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView=new TextView(this);
setContentView(textView);
SpannableString showString = new SpannableString("1234533333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336");
MyIm imageSpan=new MyIm(this, R.drawable.ic_launcher);
MyIm imageSpan2=new MyIm(this, R.drawable.ic_launcher);
MyIm imageSpan21=new MyIm(this, R.drawable.ic_launcher);
showString.setSpan(imageSpan, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
showString.setSpan(imageSpan2, 27, 30, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
showString.setSpan(imageSpan21, 77, 78, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(showString);
}
public class MyIm extends ImageSpan
{
public MyIm(Context arg0,int arg1) {
super(arg0, arg1);
}
public int getSize(Paint paint, CharSequence text, int start, int end,
FontMetricsInt fm) {
Drawable d = getDrawable();
Rect rect = d.getBounds();
if (fm != null) {
FontMetricsInt fmPaint=paint.getFontMetricsInt();
int fontHeight = fmPaint.bottom - fmPaint.top;
int drHeight=rect.bottom-rect.top;
int top= drHeight/2 - fontHeight/4;
int bottom=drHeight/2 + fontHeight/4;
fm.ascent=-bottom;
fm.top=-bottom;
fm.bottom=top;
fm.descent=top;
}
return rect.right;
}
@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 = 0;
transY = ((bottom-top) - b.getBounds().bottom)/2+top;
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
}
}