anroid textview 文本后拼接自己生成的动态图片

项目中有如题的需求:

网上看了好多也都有些问题。最终找到正确方法,如下:

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);

    }
});

这样三步就可以满足需求了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章