项目中有如题的需求:
网上看了好多也都有些问题。最终找到正确方法,如下:
1.要生成一个拼接的动态图片的Bitmap。这里的思路是将布局转换成Bitmap,这个布局可以是通过LayoutInflater.inflate得来的,也可以是直接在Activity 或者fragment的布局中显示出来的。如下便是生成bitmap的工具方法。经实验有效:
public synchronized static Bitmap getBitmapFrom(View contentView) { Bitmap bit = null; try { contentView.setLayoutParams(new ViewGroup.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); contentView.setDrawingCacheEnabled(true); contentView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); contentView.layout(0, 0, contentView.getMeasuredWidth(), contentView.getMeasuredHeight()); contentView.buildDrawingCache(); bit = contentView.getDrawingCache(); if (bit == null) { contentView.setDrawingCacheEnabled(true); bit = Bitmap.createBitmap(contentView.getWidth(), contentView.getHeight(), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bit); c.translate(-contentView.getScrollX(), -contentView.getScrollY()); contentView.draw(c); return bit; } } catch (Exception e) { e.printStackTrace(); } return bit; }
2.要在TextView 末尾拼接图片,那就可以用到ImageSpan,如下:
public class VerticalImageSpan extends ImageSpan { public VerticalImageSpan(Drawable drawable) { super(drawable); } public VerticalImageSpan(Drawable d, String source) { super(d, source); } public VerticalImageSpan(Context context, int resourceId) { super(context, resourceId); } /** * update the text line height */ @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fontMetricsInt) { Drawable drawable = getDrawable(); Rect rect = drawable.getBounds(); if (fontMetricsInt != null) { Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt(); int fontHeight = fmPaint.descent - fmPaint.ascent; int drHeight = rect.bottom - rect.top; int centerY = fmPaint.ascent + fontHeight / 2; fontMetricsInt.ascent = centerY - drHeight / 2; fontMetricsInt.top = fontMetricsInt.ascent; fontMetricsInt.bottom = centerY + drHeight / 2; fontMetricsInt.descent = fontMetricsInt.bottom; } return rect.right; } /** * see detail message in android.text.TextLine * * @param canvas the canvas, can be null if not rendering * @param text the text to be draw * @param start the text start position * @param end the text end position * @param x the edge of the replacement closest to the leading margin * @param top the top of the line * @param y the baseline * @param bottom the bottom of the line * @param paint the work paint */ @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { Drawable drawable = getDrawable(); canvas.save(); Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt(); int fontHeight = fmPaint.descent - fmPaint.ascent; int centerY = y + fmPaint.descent - fontHeight / 2; int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2; canvas.translate(x, transY); drawable.draw(canvas); canvas.restore(); } }
3.因为是动态生成的图片,所以用ImageSpan 拼接的时候也是需要动态的获取drawable 的宽高的,那么我们便可以在Activity 或者Fragment 中为一个TextView aTextView 设置相同的文本(因为只有布局加载出来才能拿到宽高),通过监听TextView 的绘制完成方法,来拿到aTextView的宽高,进而给drawable 设置宽高,如下:
Drawable drawable = new BitmapDrawable(null, bitmap); //mTvPeroid 是设置的显示在Activity 中的TextView 但是我们看不见,通过mTvPeroid 来拿到宽高。 ViewTreeObserver observer = mTvPeroid.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mTvPeroid.getViewTreeObserver().removeOnGlobalLayoutListener(this); int height = mTvPeroid.getHeight(); int width = mTvPeroid.getWidth(); //这一步很重要,没有这一步,图片就无法正常显示。 drawable.setBounds(0, 0, width, height); VerticalImageSpan span = new VerticalImageSpan(drawable); SpannableString ss = new SpannableString(" "); ss.setSpan(span, 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //拼接图片 mTvGroupName.append(" "); mTvGroupName.append(ss); } });
这样三步就可以满足需求了。