how to overlay image with multiline text(text will

2019-06-04 07:48发布

I am developing photography apps in that I overlay an image with text.

Here is my code:

Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),
        R.drawable.themes11);
// create a mutable bitmap with the same size as the background image's size
bmOverlay = Bitmap.createBitmap(mBitmap.getWidth(),
        mBitmap.getHeight(), Bitmap.Config.ARGB_4444);
// create a canvas on which to draw
Canvas canvas = new Canvas(bmOverlay);
TextPaint paint = new TextPaint();
paint.setColor(Color.RED);

paint.setTextSize(40);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
// if the background image is defined in main.xml, omit this line
canvas.drawBitmap(mBitmap, 0, 0, null);

// draw the text and the point
canvas.drawPoint(50, 100, paint);
// canvas.drawText(InstaTextActivity.CurrentWord, 300, 200, paint);
StaticLayout layout = new StaticLayout(InstaTextActivity.CurrentWord,
        paint, display.getHeight(),
        android.text.Layout.Alignment.ALIGN_NORMAL, (float) 1.0,
        (float) 0.0, true);

canvas.translate(width / 5, height / 5);
layout.draw(canvas);
imageview_img.setImageBitmap(bmOverlay);

In this code I overlay the text on screen width/2 and height/2 it will display on top the image but I want the text to be center-aligned. Also when I write a large text it will align form center to right.

Have a look at the images to see how I want it:

The Image Background:

Backgorund Image

And the result I want:

result

4条回答
对你真心纯属浪费
2楼-- · 2019-06-04 08:22

Use the below methods to measure the height and width of the text. Then when drawing the text on canvas

left = width/2 - textWidth/2
top = height/2 - textHeight/2

But if you need a multiple line text for long texts, it will be a bit tricky.

/**
 * Method to get the height of the paint
 * 
 * @param brush The TextPaint used to paint the text
 * @param text The text which needs to be measured
 * @return height of the text
 */
public static int measureTextHeight(Paint brush, String text) {
    Rect result = new Rect();
    // Measure the text rectangle to get the height
    brush.getTextBounds(text, 0, text.length(), result);
    return result.height();
}
/**
 * Method to get the width of the paint
 * 
 * @param brush The TextPaint used to paint the text
 * @param text The text which needs to be measured
 * @return width of the text
 */
public static int measureTextWidth(Paint brush, String text) {
    Rect result = new Rect();
    // Measure the text rectangle to get the height
    brush.getTextBounds(text, 0, text.length(), result);
    return result.width();
}
查看更多
做自己的国王
3楼-- · 2019-06-04 08:28

This is not a very refined approach(Not optimized for memory usage) but does the job. You will need to modify the code in order to split at the string keeping words intact. Hope this helps.

package org.edu.abhi;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;

/**
 * @author Abhishek_Nandi
 * 
 */
public class DummyUserSpace extends View {

    /***************************************************************************
     * Calls superclass constructor. This will call {@link #init(Context)}
     * 
     * @param context
     *            The Context the view is running in, through which it can
     *            access the current theme, resources, etc.
     **************************************************************************/
    public DummyUserSpace(Context context) {
        super(context);
        init(context);
    }

    /***************************************************************************
     * Calls superclass constructor. This will call {@link #init(Context)}
     * 
     * @param context
     *            The Context the view is running in, through which it can
     *            access the current theme, resources, etc.
     * @param attrs
     *            The attributes of the XML tag that is inflating the view.
     * @param defStyle
     *            The default style to apply to this view. If 0, no style will
     *            be applied (beyond what is included in the theme). This may
     *            either be an attribute resource, whose value will be retrieved
     *            from the current theme, or an explicit style resource.
     **************************************************************************/
    public DummyUserSpace(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /***************************************************************************
     * Calls superclass constructor. This will call {@link #init(Context)}
     * 
     * @param context
     *            The Context the view is running in, through which it can
     *            access the current theme, resources, etc.
     * @param attrs
     *            The attributes of the XML tag that is inflating the view.
     **************************************************************************/
    public DummyUserSpace(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    /**
     * Width of the View
     */
    int viewWidth = 0;
    /**
     * Height of the View
     */
    int viewHeight = 0;

    /**
     * {@link Paint} which is used to draw {@link #text}
     */
    Paint textPaint;
    /**
     * The text which needs to be drawn
     */
    String text = "can be spared the burden of having to perform manual memory management. In some languages, memory for the creation of objects is implicitly allocated on the stack, or explicitly allocated and deallocated from the heap. In the latter case the responsibility of managing memory resides with the programmer. If the program does not deallocate an object, a memory leak occurs. If the program attempts to access or deallocate memory that has already been deallocated, the result is undefined and difficult to predict, and the program is likely to become unstable and/or crash. This can be partially remedied by the use of smart pointers, but these add overhead and complexity. Note that garbage collection does not prevent \"logical\" memory leaks, i.e. those where the memory is still referenced but never used.. o have as few implementation dependencies as possible. It is intended to let application developers \"write once, run anywhere\" (WORA), meaning that code that runs on one platform does not need to be recompiled to run on another. Java is as of 2012 one of the most popular programming languages in use, particularly for client-server web applications, with a reported 10 million users";

    /**
     * Common constructor routine
     * 
     * @param context
     *            The Context the view is running in. It is used to get the
     *            density of the device
     */
    private void init(Context context) {
        textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setTextSize(40);
        textPaint.setStrokeWidth(6.0f);
        WindowManager manager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        padding *= outMetrics.density;
        lineSpacing *= outMetrics.density;
    }

    /**
     * Split the string and compute the {@link #startY}, {@link #textHeight}
     * which is required for drawing the view
     */
    private void prepareForDrawing() {
        viewWidth = getWidth();
        viewHeight = getHeight();
        if (viewHeight == 0) {
            return;
        }

        textHeight = Utility.measureTextHeight(textPaint, text);
        if (0 == textHeight) {
            return;
        }
        maxLines = (viewHeight - 2 * padding) / (textHeight + lineSpacing);
        prepareMultiLineText(textPaint, text);
        int noOfLines = splittedText.size();
        int section = noOfLines / 2;
        int center = viewHeight / 2;
        if (noOfLines % 2 == 0) {
            center -= lineSpacing / 2;
        } else {
            center -= textHeight / 2;
        }
        startY = center - (section - 1) * (textHeight + lineSpacing)
                + lineSpacing;
    }

    /**
     * The starting position from where the view will start drawing
     */
    private int startY = 0;
    /**
     * Height of the text
     */
    private int textHeight = 0;
    /**
     * Maximum lines this view can hold
     */
    private int maxLines = 1;
    /**
     * Padding from the view border
     */
    private int padding = 20;
    /**
     * Spacing between each line
     */
    private int lineSpacing = 10;

    private final String loadingText = "Loading..";

    /*
     * (non-Javadoc)
     * 
     * @see android.view.View#onDraw(android.graphics.Canvas)
     */
    @Override
    protected void onDraw(Canvas canvas) {
        if (!computationComplete) {
            new DrawComputations().execute();
            canvas.drawText(
                    loadingText,
                    getWidth() / 2
                            - Utility.measureTextWidth(textPaint, loadingText)
                            / 2,
                    getHeight() / 2
                            - Utility.measureTextHeight(textPaint, loadingText)
                            / 2, textPaint);
        } else {
            for(int count = 0; count<splittedText.size() ; count++){
                String trimmed = splittedText.get(count);
                //System.out.println(trimmed);
                canvas.drawText(
                        trimmed,
                        viewWidth / 2
                                - Utility.measureTextWidth(textPaint, trimmed)
                                / 2, startY + (count - 1)
                                * (textHeight + lineSpacing), textPaint);
            }
        }

    }

    /**
     * Denotes the computation has completed and the view is ready to be drawn
     */
    boolean computationComplete = false;

    /**
     * This {@link AsyncTask} performs the computation in background and updates
     * the view when computation is finished and the view is ready to be drawn
     * 
     * @author Abhishek_nandi
     * @version 1.0
     */
    class DrawComputations extends AsyncTask<Void, Void, Void> {

        /*
         * (non-Javadoc)
         * 
         * @see android.os.AsyncTask#doInBackground(Params[])
         */
        @Override
        protected Void doInBackground(Void... params) {
            prepareForDrawing();
            computationComplete = true;
            return null;
        }

        /*
         * (non-Javadoc)
         * 
         * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
         */
        @Override
        protected void onPostExecute(Void result) {
            invalidate();
        }
    }

    /**
     * Collection which holds the multi-line text
     */
    private List<String> splittedText = new ArrayList<String>();

    /**
     * This method is responsible for stripping {@link #text} into individual
     * lines in order to form the multi line text. This method can be used as a
     * utility.
     * 
     * @param paint
     *            The {@link Paint} which is used to draw the text
     * @param str
     *            The string which needs to be stripped
     */
    private void prepareMultiLineText(Paint paint, String str) {
        if (str == null || str.trim().length() == 0)
            return;
        str = str.trim();
        String result = str;
        int boxWidth = viewWidth;
        try {
            float textWidth = paint.measureText(str) + 2 * padding;
            result = str;
            while (textWidth > boxWidth) {
                if (result.length() == 0)
                    break;//keeping the entire word intact//if(result.lastIndexOf(" ")!=-1){result = result.substring(0, result.lastIndexOf(" "))}else
                result = result.substring(0, result.length() - 1);
                textWidth = paint.measureText(result) + 2 * padding;
            }
            result = result.trim();
            boolean exceeded = false;
            if (splittedText.size() == maxLines) {
                exceeded = true;
                result = result.substring(0, result.length()-2).concat("..");
            }
            splittedText.add(result);
            if (!exceeded && result.length() != str.length()) {
                prepareMultiLineText(textPaint, str.substring(result.length()));
            }
        } catch (Exception e) {
            Log.e("CustomView", "prepareMultiLineText", e);
        }
    }

} // END of class
// END of file

This is how it looks

查看更多
我命由我不由天
4楼-- · 2019-06-04 08:34

i using this. working for me.

public Bitmap drawMultilineTextToBitmap(Context gContext,
                                   int gResId,
                                   String gText) {

  // prepare canvas
  Resources resources = gContext.getResources();
  float scale = resources.getDisplayMetrics().density;
  Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);

  android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
  // set default bitmap config if none
  if(bitmapConfig == null) {
    bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
  }
  // resource bitmaps are imutable,
  // so we need to convert it to mutable one
  bitmap = bitmap.copy(bitmapConfig, true);

  Canvas canvas = new Canvas(bitmap);

  // new antialiased Paint
  TextPaint paint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
  // text color - #3D3D3D
  paint.setColor(Color.rgb(61, 61, 61));
  // text size in pixels
  paint.setTextSize((int) (14 * scale));
  // text shadow
  paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);

  // set text width to canvas width minus 16dp padding
  int textWidth = canvas.getWidth() - (int) (16 * scale);

  // init StaticLayout for text
  StaticLayout textLayout = new StaticLayout(
    gText, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);

  // get height of multiline text
  int textHeight = textLayout.getHeight();

  // get position of text's top left corner
  float x = (bitmap.getWidth() - textWidth)/2;
  float y = (bitmap.getHeight() - textHeight)/2;

  // draw text to the Canvas center
  canvas.save();
  canvas.translate(x, y);
  textLayout.draw(canvas);
  canvas.restore();

  return bitmap;
}

source : http://www.skoumal.net/en/android-drawing-multiline-text-on-bitmap/

查看更多
兄弟一词,经得起流年.
5楼-- · 2019-06-04 08:40

You should use StaticLayout for this. It measures and draws multiline text, handling line wrapping, line spacing, alignment etc.

StaticLayout layout = new StaticLayout("your long text", textPaint,
    pixelsToFitWidthTo, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, true);
int boxHeight = layout.getHeight(); // measure

The text can even be HTML formatted, just wrap your text in Html.fromHtml():

Html.fromHtml("your long <b>and bold</b> text");
查看更多
登录 后发表回答