五種方法:
- drawableLeft、drawableTop。。(TextView中xml自帶,通過drawPadding控制間距)
- 自定義TextView,重寫TextView的Ondraw方法
BitmapFactory獲取bitmap對象
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, getPaint());
super.onDraw(canvas);
}
缺點:不能靈活控制圖片位置
- 使用html,安卓api支持
textView = (TextView) findViewById(R.id.tv);
String html = "<img src='" + R.drawable.ding + "'/>";
html += " <img src='" + R.drawable.jing + "' />";
ImageGetter imgGetter = new ImageGetter() {
@Override
public Drawable getDrawable(String source) {
// TODO Auto-generated method stub
int id = Integer.parseInt(source);
Drawable d = getResources().getDrawable(id);
d.setBounds(0, 0, d.getIntrinsicWidth() + 10, d.getIntrinsicHeight() + 10);
return d;
}
};
CharSequence charSequence = Html.fromHtml(html, imgGetter, null);
textView.setText(charSequence);
textView.append(" Html實現(xiàn)圖文混排");
- imageSpan
textViewImageSpan= (TextView) findViewById(R.id.textViewImageSpan);
Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
//根據(jù)Bitmap對象創(chuàng)建ImageSpan對象
ImageSpan imageSpan=new ImageSpan(this,bitmap);
//創(chuàng)建一個SpinnableString對象,以便插入ImageSpan對象封裝的圖像
SpannableString spannableString=new SpannableString("replace");
//用ImageSpan對象替換replace字符串
spannableString.setSpan(imageSpan,0,7, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
//將圖像顯示在TextView上
textViewImageSpan.setText(spannableString);
- 擴展圖片文字單行之間居中(間距字體大小都不影響)
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.tv);
SpannableString showString = new SpannableString(
"我 鐘山風雨起蒼黃百萬雄師過大江虎踞龍盤今勝昔天翻地覆慨而慷宜將剩勇追窮寇不可沽名學霸王天若有情天亦老人間正道是滄桑。鐘山風雨起蒼黃百萬雄師過大江虎踞龍盤今勝昔天翻地覆慨而慷宜將剩勇追窮寇不可沽名學霸王天若有情天亦老人間正道是滄桑。");
MyIm imageSpan = new MyIm(this, R.drawable.ding);
MyIm imageSpan2 = new MyIm(this, R.drawable.jing);
showString.setSpan(imageSpan, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
showString.setSpan(imageSpan2, 0, 1, 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;
}
//getSize方法,返回一個Int含義為圖片的寬度還設置了文字的ascent、descent的位置
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom,
@NonNull Paint paint) {
Drawable b = getDrawable();
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2;
canvas.save();
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
}
先解釋一個類:Paint.FontMetrics,它表示繪制字體時的度量標準。google的官方api文檔對它的字段說明如下:
ascent: 字體最上端到基線的距離
descent:字體最下端到基線的距離

Paste_Image.png
回到主題,我們要讓imagespan與text對齊,只需把imagespan放到descent線和ascent線之間的中間位置就可以了。
解釋下形參:
x,要繪制的image的左邊框到textview左邊框的距離。
y,要替換的文字的基線坐標,即基線到textview上邊框的距離。
top,替換行的最頂部位置。
bottom,替換行的最底部位置。注意,textview中兩行之間的行間距是屬于上一行的,所以這里bottom是指行間隔的底部位置。
paint,畫筆,包含了要繪制字體的度量信息。
這幾個參數(shù)含義在代碼中找不到說明,寫了個demo測出來的。top和bottom參數(shù)只是解釋下,函數(shù)里面用不上。
然后解釋下代碼邏輯:
getDrawable獲取要繪制的image,getBounds是獲取包裹image的矩形框尺寸;
y + fm.descent得到字體的descent線坐標;
y + fm.ascent得到字體的ascent線坐標;
兩者相加除以2就是兩條線中線的坐標;
b.getBounds().bottom是image的高度(試想把image放到原點),除以2即高度一半;
前面得到的中線坐標減image高度的一半就是image頂部要繪制的目標位置;
最后把目標坐標傳遞給canvas.translate函數(shù)就可以了
顯示效果:

Paste_Image.png