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

    }
});

這樣三步就可以滿足需求了。

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