Zeichnen Sie mehrzeiligen Text auf Leinwand

124

Eine hoffentlich schnelle Frage, aber ich kann anscheinend keine Beispiele finden ... Ich möchte mehrzeiligen Text Viewüber a in einen Benutzer schreiben Canvas, und in habe onDraw()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 das sein \nwürde.

Alle Hinweise geschätzt.

Paul

Paul Mennega
quelle
1
In der Dokumentation wird empfohlen, a zu verwenden, Layoutanstatt Canvas.drawTextdirekt anzurufen . Diese Fragen und Antworten zeigen, wie Sie mit aStaticLayout mehrzeiligen Text zeichnen.
Suragch

Antworten:

26

Leider weiß Android nicht was \nist. Was Sie tun müssen, ist \ndas Y zu entfernen und dann das Y zu versetzen, um Ihren Text in die nächste Zeile zu bekommen. Also so etwas wie das:

canvas.drawText("This is", 100, 100, mTextPaint);
canvas.drawText("multi-line", 100, 150, mTextPaint);
canvas.drawText("text", 100, 200, mTextPaint);
Icemanind
quelle
1
Also müsste ich den Text in drei separate Teile aufteilen und dann drei Anrufe tätigen drawText()?
Paul Mennega
5
Ja. Ich habe gerade ein Beispiel hinzugefügt. Verwenden Sie String.Split, um die '\ n' zu teilen und dann jede zu versetzen.
Icemanind
Vielen Dank für diese Idee.
Sumit Kumar
224

Ich habe einen anderen Weg gefunden, statische Layouts zu verwenden. Der Code ist für jedermann zugänglich:

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();
GreenBee
quelle
3
meiner Meinung nach bessere Lösung. Keine Notwendigkeit, Text in Zeilen aufzuteilen. Besonders praktisch, wenn Text zu Beginn keine Zeilenumbrüche aufweist oder wir nicht wissen, ob sie vorhanden sind.
Ewoks
6
Super, es hat bei mir funktioniert. Können wir verhindern, dass großer Text die Leinwandhöhe überschreitet?
MoDev
1
Sehr hilfreich, aber achten Sie beim Zentrieren des StaticLayout darauf, wie Sie die Ausrichtung auf TextPaint () festlegen. Die Verwendung von TextPaing.setTextAlign (Align.CENTER) verursachte Probleme für mich, da verschiedene Telefone unterschiedliche Dinge damit tun.
Greg7gkb
2
canvas.getWidth()sollte wirklich sein getWidth() - getPaddingLeft() - getPaddingRight(), um die Auffüllung der Ansicht zu berücksichtigen. Beachten Sie außerdem, dass Sie das StaticLayout nur berechnen können, wenn sich Ihr Text oder Ihre Ansichtsgröße ändert, und zeichnen Sie es, ohne ein neues zu erstellen, was wahrscheinlich besser ist!
Jules
1
@Eenvincible Sie können meinen Blogpost hier überprüfen: skoumal.net/en/android-drawing-multiline-text-on-bitmap
gingo
98

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();
}
Dave
quelle
Gibt es eine gute Möglichkeit, die neue y-Position zu berechnen? Das Hinzufügen einer scheinbar zufälligen Zahl macht mich nicht sehr wohl ...
AgentKnopf
1
Wenn Sie der Meinung sind, dass Aufstieg + anständig zu klein ist, können Sie einen konstanten Lückenfaktor hinzufügen oder nach Belieben multiplizieren (z. B. mit 1,5 Zeilen).
Dave
1
Beachten Sie, dass der Aufstieg negativ ist. Sie brauchen tatsächlich Abstieg, um die Höhe zu erreichen
Amir Uval
1
Sie können die Metriken für ein ausgewähltes Zeichen abrufen, z. B. font.measure ("Y")
GregD
11

Ich habe ein vollständiges Beispiel geschrieben

Geben Sie hier die Bildbeschreibung ein

Farben.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;
    }
}
Siddhpura Amit
quelle
4
Warum sollten Sie eine Schleife verwenden, um Zeilen zu zählen? int noOfLines = gText.split("\n").length
Tomasz
9

Dies ist meine Lösung, die auf @ Daves Antwort 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 es lässt dich nicht wirklich. Das ist also eine Zwischenklasse!

Noelicus
quelle
1
Ich habe es auf diese Weise versucht. Alles funktioniert einwandfrei, außer dass meine größte Zeile, das letzte Wort, das letzte Zeichen nur zur Hälfte angezeigt wird. ?
Aada
8

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);
   }
}
Lumis
quelle
6

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/

Premkumar Manipillai
quelle
während ich Bitmap verwende image = BitmapFactory.decodeResource (mContext.getResources (), R.drawable.transparent_flag); es funktioniert gut, aber wenn ich eine installierte Textansicht-ID verwende, funktioniert es nicht
DKV
Danke, es hat genau so funktioniert, wie ich es wollte, aber wenn Sie mir helfen können, den Text darin zu bearbeiten oder an eine andere Position zu schieben, wie es der Fotoladen tut, dann nochmals vielen Dank im Voraus.
Kvadityaaz
5

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

Richard
quelle
2
Ich denke du meinst Paint.getFontSpacing
Jose M.
5

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);
Sunil Kumar
quelle
6
Ich denke, dies ist das perfekte Beispiel dafür, was man in onDraw NICHT tun sollte.
Rupps
@rupps Ja, es mag ein völliger Overkill sein, all dies in onDraw aufzunehmen, aber die Antwort sagt Ihnen nicht, dass Sie dies tun sollen. Und die Idee ist genial (und hat mein Problem gelöst). Schrauben Sie StaticLayout und String.split!
Rodia
4

Ich habe die von GreenBee vorgeschlagene Lösung erneut verwendet und eine Funktion zum Zeichnen von mehrzeiligem Text in bestimmte Grenzen mit dem "..." am Ende erstellt, wenn ein Abschneiden aufgetreten ist:

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();
    }
androidseb
quelle
3
Wenn der Text abgeschnitten wird, schneidet Ihr Code möglicherweise ein ganzes Wort, das ebenfalls in das Leerzeichen passt. Hier ist ein kleiner Vorschlag zur Verbesserung Ihres Codes: Ersetzen Sie die drei Zeichen "..." durch nur eines, das die drei Punkte enthält: "..." (der & hellip; Code in HTML). Sie können dann nur ein Zeichen (häufig ein Leerzeichen) anstelle von drei entfernen und Ihr Wort ungeschnitten lassen: truncatedText = truncatedText.substring (0, Math.max (0, truncatedText.length () - 1));
Asterius
2

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

            }
        }
    }
römisch
quelle
2

Ich arbeitete mit dem, was ich hatte, das bereits einzelne Zeilen in Leinwände umwandelte, und ich arbeitete Lumis 'Antwort ab, und am Ende kam ich dazu. 1.3 und 1.3f sind als Auffüllung zwischen Zeilen im Verhältnis zur Schriftgröße gedacht.

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;
}
Peter Griffin
quelle
0

Ich hatte ein ähnliches Problem. aber ich sollte den Pfad des Textes zurückgeben. Sie können diesen Pfad auf Leinwand zeichnen. Das ist mein Code. Ich benutze Break Text. und path.op

           public Path createClipPath(int width, int height) {
            final Path path = new Path();
            if (textView != null) {
                mText = textView.getText().toString();
                mTextPaint = textView.getPaint();
                float text_position_x = 0;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                    text_position_x = findTextBounds(textView).left;

                }
                boolean flag = true;
                int line = 0;
                int startPointer = 0;
                int endPointer = mText.length();

                while (flag) {
                    Path p = new Path();
                    int breakText = mTextPaint.breakText(mText.substring(startPointer), true, width, null);
                    mTextPaint.getTextPath(mText, startPointer, startPointer + breakText, text_position_x,
                            textView.getBaseline() + mTextPaint.getFontSpacing() * line, p);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        path.op(p, Path.Op.UNION);
                    }
                    endPointer -= breakText;
                    startPointer += breakText;
                    line++;
                    if (endPointer == 0) {
                        flag = false;
                    }
                }

            }
            return path;
        }

und um textgebundenen Text zu finden, habe ich diese Funktion verwendet

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
private Rect findTextBounds(TextView textView) {
    // Force measure of text pre-layout.
    textView.measure(0, 0);
    String s = (String) textView.getText();

    // bounds will store the rectangle that will circumscribe the text.
    Rect bounds = new Rect();
    Paint textPaint = textView.getPaint();

    // Get the bounds for the text. Top and bottom are measured from the baseline. Left
    // and right are measured from 0.
    textPaint.getTextBounds(s, 0, s.length(), bounds);
    int baseline = textView.getBaseline();
    bounds.top = baseline + bounds.top;
    bounds.bottom = baseline + bounds.bottom;
    int startPadding = textView.getPaddingStart();
    bounds.left += startPadding;

    // textPaint.getTextBounds() has already computed a value for the width of the text,
    // however, Paint#measureText() gives a more accurate value.
    bounds.right = (int) textPaint.measureText(s, 0, s.length()) + startPadding;
    return bounds;
}
Mohandes
quelle
0

Zusätzlich zum Zeichnen von mehrzeiligem Text kann es schwierig sein, die mehrzeiligen Textgrenzen zu ermitteln (z. B. um sie auf Leinwand auszurichten).
Standardpaint.getTextBounds() funktioniert in diesem Fall nicht, da die einzige Zeile gemessen wird.

Der Einfachheit halber habe ich diese beiden Erweiterungsfunktionen erstellt: eine zum Zeichnen von mehrzeiligem Text und die andere zum Abrufen von Textgrenzen.

private val textBoundsRect = Rect()

/**
 * Draws multi-line text on the Canvas with the origin at (x,y), using the specified paint. The origin is interpreted
 * based on the Align setting in the paint.
 *
 * @param text The text to be drawn
 * @param x The x-coordinate of the origin of the text being drawn
 * @param y The y-coordinate of the baseline of the text being drawn
 * @param paint The paint used for the text (e.g. color, size, style)
 */
fun Canvas.drawTextMultiLine(text: String, x: Float, y: Float, paint: Paint) {
    var lineY = y
    for (line in text.split("\n")) {
        lineY += paint.descent().toInt() - paint.ascent().toInt()
        drawText(line, x, lineY, paint)
    }
}

/**
 * Retrieve the text boundary box, taking into account line breaks [\n] and store to [boundsRect].
 *
 * Return in bounds (allocated by the caller [boundsRect] or default mutable [textBoundsRect]) the smallest rectangle that
 * encloses all of the characters, with an implied origin at (0,0).
 *
 * @param text string to measure and return its bounds
 * @param start index of the first char in the string to measure. By default is 0.
 * @param end 1 past the last char in the string to measure. By default is test length.
 * @param boundsRect rect to save bounds. Note, you may not supply it. By default, it will apply values to the mutable [textBoundsRect] and return it.
 * In this case it will be changed by each new this function call.
 */
fun Paint.getTextBoundsMultiLine(
    text: String,
    start: Int = 0,
    end: Int = text.length,
    boundsRect: Rect = textBoundsRect
): Rect {
    getTextBounds(text, start, end, boundsRect)
    val linesCount = text.split("\n").size
    val allLinesHeight = (descent().toInt() - ascent().toInt()) * linesCount
    boundsRect.bottom = boundsRect.top + allLinesHeight
    return boundsRect
}

So einfach ist das jetzt: Zum Zeichnen von mehrzeiligem Text:

canvas.drawTextMultiLine(text, x, y, yourPaint)

Zum Messen von Text:

val bounds = yourPaint.getTextBoundsMultiLine (Text)

In diesem Fall wird der gesamte Text vom Anfang bis zum Ende und unter Verwendung der Standardeinstellung für einmal zugewiesenes (veränderbares) Rechteck gemessen.
Sie können mit der Übergabe zusätzlicher Parameter für zusätzliche Flexibilität herumspielen.

Leo Droidcoder
quelle
-1

Mein Beispiel mit dynamischer Textgröße und -abstand funktioniert hervorragend für mich ...

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