wake-up-neo.net

Zeichnen Sie mehrzeiligen Text in Canvas

Eine hoffentlich schnelle Frage, aber ich kann anscheinend keine Beispiele finden ... Ich möchte mehrzeiligen Text über eine View in eine benutzerdefinierte Canvas schreiben, und in onDraw() habe ich:

...
String text = "This is\nmulti-line\ntext";
canvas.drawText(text, 100, 100, mTextPaint);
...

Ich hatte gehofft, dass dies zu Zeilenumbrüchen führen würde, aber stattdessen sehe ich kryptische Zeichen, wo der \n wäre.

Alle Hinweise haben es zu schätzen gewusst.

Paul

101
Paul Mennega

Leider weiß Android nicht, was \n ist. Was Sie tun müssen, ist, den \n zu entfernen und dann das Y zu verschieben, um den Text in der nächsten Zeile anzuzeigen. Also so etwas wie:

canvas.drawText("This is", 100, 100, mTextPaint);
canvas.drawText("multi-line", 100, 150, mTextPaint);
canvas.drawText("text", 100, 200, mTextPaint);
24
Icemanind

Ich habe einen anderen Weg gefunden, statische Layouts zu verwenden. Der Code ist hier, auf den sich jeder beziehen kann:

TextPaint mTextPaint=new TextPaint();
StaticLayout mTextLayout = new StaticLayout(mText, mTextPaint, canvas.getWidth(), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);

canvas.save();
// calculate x and y position where your text will be placed

textX = ...
textY = ...

canvas.translate(textX, textY);
mTextLayout.draw(canvas);
canvas.restore();
211
GreenBee

Durchlaufen Sie einfach jede Zeile: 

int x = 100, y = 100;
for (String line: text.split("\n")) {
      canvas.drawText(line, x, y, mTextPaint);
      y += mTextPaint.descent() - mTextPaint.ascent();
}
86
Dave

Dies ist meine Lösung, die auf der Antwort von @ Dave basiert (danke übrigens ;-))

import Android.graphics.Canvas;
import Android.graphics.Paint;

public class mdCanvas
{
    private Canvas m_canvas;

    public mdCanvas(Canvas canvas)
    {
        m_canvas = canvas;
    }

    public void drawMultiline(String str, int x, int y, Paint paint)
    {
        for (String line: str.split("\n"))
        {
              m_canvas.drawText(line, x, y, Paint);
              y += -Paint.ascent() + Paint.descent();
        }
    }
}

Ich habe versucht, Canvas zu erben, aber das lässt Sie nicht wirklich zu. Das ist also eine Zwischenklasse!

9
noelicus

Ich muss hier meine Version hinzufügen, die auch STROKE WIDTH berücksichtigt.

void drawMultiLineText(String str, float x, float y, Paint paint, Canvas canvas) {
   String[] lines = str.split("\n");
   float txtSize = -Paint.ascent() + Paint.descent();       

   if (Paint.getStyle() == Style.FILL_AND_STROKE || Paint.getStyle() == Style.STROKE){
      txtSize += Paint.getStrokeWidth(); //add stroke width to the text size
   }
   float lineSpace = txtSize * 0.2f;  //default line spacing

   for (int i = 0; i < lines.length; ++i) {
      canvas.drawText(lines[i], x, y + (txtSize + lineSpace) * i, Paint);
   }
}
8
Lumis

Ich habe ein vollständiges Beispiel geschrieben 

 enter image description here

colors.xml 

  <color name="transparentBlack">#64000000</color>

Java-Klasse 

 public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.amit);
        ImageView imageView = (ImageView)findViewById(R.id.imageView);
        imageView.setImageBitmap(drawTextToBitmap(this, bm, "Name: Kolala\nDate: Dec 23 2016 12:47 PM, \nLocation: 440 Banquets & Restaurents"));

    }

  public Bitmap drawTextToBitmap(Context gContext,
                                   Bitmap bitmap,
                                   String gText) {
        Resources resources = gContext.getResources();
        float scale = resources.getDisplayMetrics().density;

        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 antialised Paint
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        // text color - #3D3D3D
        Paint.setColor(Color.WHITE);
        // text size in pixels
        Paint.setTextSize((int) (25 * scale));
        // text shadow
        Paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);

        // draw text to the Canvas center
        Rect bounds = new Rect();

        int noOfLines = 0;
        for (String line: gText.split("\n")) {
           noOfLines++;
        }

        Paint.getTextBounds(gText, 0, gText.length(), bounds);
        int x = 20;
        int y = (bitmap.getHeight() - bounds.height()*noOfLines);

        Paint mPaint = new Paint();
        mPaint.setColor(getResources().getColor(R.color.transparentBlack));
        int left = 0;
        int top = (bitmap.getHeight() - bounds.height()*(noOfLines+1));
        int right = bitmap.getWidth();
        int bottom = bitmap.getHeight();
        canvas.drawRect(left, top, right, bottom, mPaint);

        for (String line: gText.split("\n")) {
            canvas.drawText(line, x, y, Paint);
            y += Paint.descent() - Paint.ascent();
        }

        return bitmap;
    }
}
8
Siddhpura Amit

Ja. Verwenden Sie canvas.getFontSpacing() als Inkrement. Ich habe es aus Neugier ausprobiert und es funktioniert für jede Schriftgröße.

5
Richard

versuche dies

Paint paint1 = new Paint();
Paint1.setStyle(Paint.Style.FILL);
Paint1.setAntiAlias(true);
Paint1.setColor(Color.BLACK);
Paint1.setTextSize(15);


TextView tv = new TextView(context);
tv.setTextColor(Color.BLACK);
LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
llp.setMargins(5, 2, 0, 0); // llp.setMargins(left, top, right, bottom);
tv.setLayoutParams(llp);
tv.setTextSize(10);
String text="this is good to see you , i am the king of the team";

tv.setText(text);
tv.setDrawingCacheEnabled(true);
tv.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(canvas.getHeight(), MeasureSpec.EXACTLY));
tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
canvas.drawBitmap(tv.getDrawingCache(), 5, 10, Paint1);
tv.setDrawingCacheEnabled(false);
4
Sunil Kumar

Ich habe die von GreenBee vorgeschlagene Lösung wiederverwendet und eine Funktion erstellt, um mehrzeiligen Text mit der Endung "..." in angegebene Grenzen zu ziehen, wenn ein Abbruch erfolgte:

public static void drawMultiLineEllipsizedText(final Canvas _canvas, final TextPaint _textPaint, final float _left,
            final float _top, final float _right, final float _bottom, final String _text) {
        final float height = _bottom - _top;

        final StaticLayout measuringTextLayout = new StaticLayout(_text, _textPaint, (int) Math.abs(_right - _left),
                Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);

        int line = 0;
        final int totalLineCount = measuringTextLayout.getLineCount();
        for (line = 0; line < totalLineCount; line++) {
            final int lineBottom = measuringTextLayout.getLineBottom(line);
            if (lineBottom > height) {
                break;
            }
        }
        line--;

        if (line < 0) {
            return;
        }

        int lineEnd;
        try {
            lineEnd = measuringTextLayout.getLineEnd(line);
        } catch (Throwable t) {
            lineEnd = _text.length();
        }
        String truncatedText = _text.substring(0, Math.max(0, lineEnd));

        if (truncatedText.length() < 3) {
            return;
        }

        if (truncatedText.length() < _text.length()) {
            truncatedText = truncatedText.substring(0, Math.max(0, truncatedText.length() - 3));
            truncatedText += "...";
        }
        final StaticLayout drawingTextLayout = new StaticLayout(truncatedText, _textPaint, (int) Math.abs(_right
                - _left), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);

        _canvas.save();
        _canvas.translate(_left, _top);
        drawingTextLayout.draw(_canvas);
        _canvas.restore();
    }
3
androidseb

es wird klappen. Ich habe getestet 

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

Quelle: http://www.skoumal.net/de/Android-drawing-multiline-text-on-bitmap/

Lösung ohne StaticLayout

//Get post text
    String text = post.getText();

    //Get weight of space character in px
    float spaceWeight = Paint.measureText(" ");

    //Start main algorithm of drawing words on canvas
    //Split text to words
    for (String line : text.split(" ")) {
        //If we had empty space just continue
        if (line.equals("")) continue;
        //Get weight of the line
        float lineWeight = Paint.measureText(line);
        //If our Word(line) doesn't have any '\n' we do next
        if (line.indexOf('\n') == -1) {
            //If Word can fit into current line
            if (cnv.getWidth() - pxx - defaultMargin >= lineWeight) {
                //Draw text
                cnv.drawText(line, pxx, pxy, Paint);
                //Move start x point to Word weight + space weight
                pxx += lineWeight + spaceWeight;
            } else {
                //If Word can't fit into current line
                //Move x point to start
                //Move y point to the next line
                pxx = defaultMargin;
                pxy += Paint.descent() - Paint.ascent();
                //Draw
                cnv.drawText(line, pxx, pxy, Paint);
                //Move x point to Word weight + space weight
                pxx += lineWeight + spaceWeight;
            }
            //If line contains '\n'
        } else {
            //If '\n' is on the start of the line
            if (line.indexOf('\n') == 0) {
                pxx = defaultMargin;
                pxy += Paint.descent() - Paint.ascent();
                cnv.drawText(line.replaceAll("\n", ""), pxx, pxy, Paint);
                pxx += lineWeight + spaceWeight;
            } else {
                //If '\n' is somewhere in the middle
                //and it also can contain few '\n'
                //Split line to sublines
                String[] subline = line.split("\n");
                for (int i = 0; i < subline.length; i++) {
                    //Get weight of new Word
                    lineWeight = Paint.measureText(subline[i]);
                    //If it's empty subline that's mean that we have '\n'
                    if (subline[i].equals("")) {
                        pxx = defaultMargin;
                        pxy += Paint.descent() - Paint.ascent();
                        cnv.drawText(subline[i], pxx, pxy, Paint);
                        continue;
                    }
                    //If we have only one Word
                    if (subline.length == 1 && i == 0) {
                        if (cnv.getWidth() - pxx >= lineWeight) {
                            cnv.drawText(subline[0], pxx, pxy, Paint);
                            pxx = defaultMargin;
                            pxy += Paint.descent() - Paint.ascent();
                        } else {
                            pxx = defaultMargin;
                            pxy += Paint.descent() - Paint.ascent();
                            cnv.drawText(subline[0], pxx, pxy, Paint);
                            pxx = defaultMargin;
                            pxy += Paint.descent() - Paint.ascent();
                        }
                        continue;
                    }
                    //If we have set of words separated with '\n'
                    //it is the first Word
                    //Make sure we can put it into current line
                    if (i == 0) {
                        if (cnv.getWidth() - pxx >= lineWeight) {
                            cnv.drawText(subline[0], pxx, pxy, Paint);
                            pxx = defaultMargin;
                        } else {
                            pxx = defaultMargin;
                            pxy += Paint.descent() - Paint.ascent();
                            cnv.drawText(subline[0], pxx, pxy, Paint);
                            pxx = defaultMargin;
                        }
                    } else {
                        pxx = defaultMargin;
                        pxy += Paint.descent() - Paint.ascent();
                        cnv.drawText(subline[i], pxx, pxy, Paint);
                        pxx += lineWeight + spaceWeight;
                    }
                }

            }
        }
    }
2
Roman

Ich arbeitete mit dem, was ich hatte, das bereits einzelne Zeilen in Leinwände umwandelte, und ich arbeitete die Antwort von Lumis ab, und ich endete damit. Die Zeilen 1.3 und 1.3f sind als Abstand zwischen den Zeilen und der Schriftgröße zu verstehen.

public static Bitmap getBitmapFromString(final String text, final String font, int textSize, final int textColor)
{
    String lines[] = text.split("\n");
    textSize = getRelX(textSize);  //a method in my app that adjusts the font size relative to the screen size
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Paint.setTextSize(textSize);
    Paint.setColor(textColor);
    Paint.setTextAlign(Paint.Align.LEFT);
    Typeface face = Typeface.createFromAsset(GameActivity.getContext().getAssets(),GameActivity.getContext().getString(R.string.font) + font + GameActivity.getContext().getString(R.string.font_ttf));
    Paint.setTypeface(face);
    float baseline = -Paint.ascent(); // ascent() is negative
    int width = (int) (Paint.measureText(text) + 0.5f); // round
    int height = (int) (baseline + Paint.descent() + 0.5f);
    Bitmap image = Bitmap.createBitmap(width, (int)(height * 1.3 * lines.length), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(image);
    for (int i = 0; i < lines.length; ++i)
    {
        canvas.drawText(lines[i], 0, baseline + textSize * 1.3f * i, Paint);
    }
    return image;
}
0
Peter Griffin

Mein Beispiel mit Dynamic Text Sizing und Abstand ist für mich großartig ...

public Bitmap fontTexture(String string, final Context context) {
    float text_x = 512;
    float text_y = 512;
    final float scale = context.getResources().getDisplayMetrics().density;

    int mThreshold = (int) (THRESHOLD_DIP * scale + 0.5f);

    String[] splited = string.split("\\s+");
    double longest = 0;
    for(String s:splited){
        if (s.length() > longest) {
            longest = s.length();
        }
    }
    if(longest > MAX_STRING_LENGTH) {
        double ratio = (double) MAX_STRING_LENGTH / longest;
        mThreshold = (int) ((THRESHOLD_DIP * ((float) ratio)) * scale + 0.5f);
    }

    Bitmap bitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);

    Canvas canvas = new Canvas(bitmap);

    Typeface font = Typeface.createFromAsset(context.getAssets(),
            "fonts/dotted_font.ttf");

    TextPaint mTextPaint=new TextPaint();
    mTextPaint.setColor(Color.YELLOW);
    mTextPaint.setTextAlign(Paint.Align.CENTER);
    mTextPaint.setTextSize(mThreshold);
    mTextPaint.setTypeface(font);
    StaticLayout mTextLayout = new StaticLayout(string, mTextPaint, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);

    canvas.save();

    canvas.translate(text_x, text_y);
    mTextLayout.draw(canvas);
    canvas.restore();


    return bitmap;
}
0
Thunderstick