Vẽ văn bản nhiều dòng lên Canvas


124

Một câu hỏi hy vọng nhanh chóng, nhưng dường như tôi không thể tìm thấy bất kỳ ví dụ nào ... Tôi muốn viết văn bản nhiều dòng cho một tùy chỉnh Viewthông qua một Canvas, và trong onDraw()tôi có:

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

Tôi đã hy vọng điều này sẽ dẫn đến việc ngắt dòng, nhưng thay vào đó tôi đang nhìn thấy các ký tự khó hiểu ở đâu \n.

Bất kỳ con trỏ đánh giá cao.

Paul


1
Các tài liệu khuyến nghị sử dụng Layoutthay vì gọi Canvas.drawTexttrực tiếp. Câu hỏi và trả lời này cho thấy cách sử dụng aStaticLayout để vẽ văn bản nhiều dòng.
Suragch

Câu trả lời:


26

Thật không may, Android không biết nó \nlà gì . Những gì bạn phải làm là tước \nvà sau đó bù Y để nhận văn bản của bạn trên dòng tiếp theo. Vì vậy, một cái gì đó như thế này:

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

1
Vì vậy, tôi phải chia văn bản thành ba phần riêng biệt, sau đó có ba cuộc gọi đến drawText()?
Paul Mennega

5
Đúng. Tôi chỉ thêm một ví dụ. Sử dụng String.Split để phân chia tại '\ n' và sau đó bù từng cái.
Icemanind

Cảm ơn bạn rất nhiều vì ý tưởng này.
Sumit Kumar

224

Tôi tìm thấy một cách khác bằng cách sử dụng bố trí tĩnh. Mã này ở đây cho bất cứ ai tham khảo:

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

3
Theo ý kiến ​​của tôi, giải pháp tốt hơn .. không cần phải phân chia văn bản thành các dòng .. Đặc biệt thuận tiện trong trường hợp văn bản không có bất kỳ ngắt dòng nào khi bắt đầu hoặc chúng tôi không biết nếu nó có chúng ...
Ewoks

6
Tuyệt vời, nó làm việc cho tôi. Chúng ta có thể ngăn văn bản lớn đi ra khỏi chiều cao vải không?
moDev

1
Rất hữu ích, nhưng khi căn giữa StaticLayout, hãy cẩn thận về cách bạn đặt căn chỉnh trên TextPaint (). Sử dụng TextPaing.setTextAlign (Align.CENTER) gây ra sự cố cho tôi vì các điện thoại khác nhau sẽ làm những việc khác nhau với điều này.
greg7gkb

2
canvas.getWidth()nên thực sự getWidth() - getPaddingLeft() - getPaddingRight(), để giải thích cho phần đệm của khung nhìn. Ngoài ra, lưu ý rằng bạn chỉ có thể tính toán StaticLayout khi văn bản hoặc kích thước khung nhìn của bạn thay đổi và vẽ nó mà không cần xây dựng một cái mới, có lẽ tốt hơn!
Jules

1
@Eenvincible bạn có thể kiểm tra blogpost của tôi ở đây: skoumal.net/en/android-drawing-multiline-text-on-bitmap
gingo

98

Chỉ cần lặp qua từng dòng:

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

Có một cách tốt để tính toán vị trí y mới? Thêm một số dường như ngẫu nhiên không làm tôi cảm thấy rất thoải mái ...
AgentKnopf

1
Nếu bạn cảm thấy mức tăng + khá nhỏ, bạn có thể thêm hệ số khoảng cách không đổi hoặc nhân (ví dụ: 1,5 dòng) để nếm thử.
Dave

1
chú ý rằng sự đi lên là tiêu cực. Bạn thực sự cần phải đi xuống để có được chiều cao
Amir Uval

1
Bạn có thể lấy số liệu cho một ký tự được chọn, ví dụ: font.measure ("Y")
GregD

11

Tôi đã viết ví dụ đầy đủ

nhập mô tả hình ảnh ở đây

màu sắc

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

lớp java

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

4
Tại sao bạn sẽ sử dụng một vòng lặp để đếm dòng? int noOfLines = gText.split("\n").length
Tomasz

9

Đây là giải pháp của tôi dựa trên câu trả lời của @ Dave (cảm ơn btw ;-))

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

Tôi đã cố gắng kế thừa Canvas, nhưng nó không thực sự cho phép bạn. Vì vậy, đây là một lớp giữa!


1
Tôi đã thử theo cách này .. mọi thứ đều hoạt động tốt, ngoại trừ dòng cuối cùng của tôi, ký tự cuối cùng chỉ hiển thị một nửa. ?
Aada

8

Tôi phải thêm vào đây phiên bản của tôi cũng xem xét STROKE WIDTH.

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

6

nó sẽ làm việc tôi đã thử nghiệm

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

Nguồn: http://www.skoumal.net/en/android-drawing-multiline-text-on-bitmap/


trong khi tôi sử dụng Bitmap image = BitmapFactory.decodeResource (mContext.getResource (), R.drawable.transparent_flag); nó hoạt động tốt nhưng nếu tôi sử dụng id xem văn bản thì nó sẽ không hoạt động
DKV

Cảm ơn, nó hoạt động cho chính xác tôi muốn, nhưng nếu bạn có thể giúp tôi chỉnh sửa văn bản trong đó, hoặc trượt nó sang bất kỳ vị trí nào khác, giống như cửa hàng ảnh thì sau đó lại cảm ơn trước.
kvadityaaz

5

Đúng. Sử dụng canvas.getFontSpacing()như gia số. Tôi đã thử nó vì tò mò và nó hoạt động cho mọi cỡ chữ.


2
Tôi nghĩ bạn có nghĩa là Paint.getFontSpaces
Jose M.

5

thử cái này

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

6
Tôi nghĩ rằng đây là ví dụ hoàn hảo về những gì KHÔNG nên làm trong onDraw.
rupps

@rupps Có, có thể là quá mức cần thiết để bao gồm tất cả những điều này trong onDraw, nhưng câu trả lời không cho bạn biết làm như vậy. Và ý tưởng là thiên tài (và nó đã giải quyết vấn đề của tôi). Vít StaticLayout và String.split!
Rodia

4

Tôi đã sử dụng lại giải pháp do GreenBee đề xuất và thực hiện chức năng vẽ một số văn bản nhiều dòng thành các giới hạn được chỉ định với "..." ở cuối nếu xảy ra cắt ngắn:

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
Khi văn bản bị cắt ngắn, mã của bạn cũng có thể cắt toàn bộ một từ phù hợp với không gian. Vì vậy, đây là một gợi ý nhỏ để cải thiện mã của bạn: thay thế ba ký tự "..." chỉ bằng một ký tự có chứa ba dấu chấm: "Thẻ" (mã & hellip; mã trong HTML). Sau đó, bạn chỉ có thể xóa một char (thường là khoảng trắng) thay vì ba và giữ cho từ của bạn không bị cắt: truncatedText = truncatedText.subopes (0, Math.max (0, truncatedText.length () - 1));
Asterius

2

Giải pháp không có 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

Tôi đã làm việc với những gì tôi có, đã chuyển đổi các dòng đơn thành khung vẽ và tôi đã tìm ra câu trả lời của Lumis và tôi đã kết thúc việc này. 1.3 và 1.3f có nghĩa là phần đệm giữa các dòng, liên quan đến kích thước của phông chữ.

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

Tôi phải đối mặt với vấn đề tương tự. nhưng tôi nên trả lại đường dẫn của văn bản. bạn có thể vẽ đường dẫn này trên Canvas. đây là mã của tôi Tôi sử dụng Break Text. và 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;
        }

và để tìm văn bản bị ràng buộc, tôi đã sử dụng chức năng này

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


0

Ngoài việc vẽ văn bản nhiều dòng, người ta có thể đấu tranh với việc giới hạn văn bản đa dòng (ví dụ để căn chỉnh nó trên khung vẽ).
Mặc định paint.getTextBounds()sẽ không hoạt động trong trường hợp này vì nó sẽ đo dòng duy nhất.

Để thuận tiện, tôi đã tạo 2 hàm mở rộng này: một để vẽ văn bản nhiều dòng và hai là để lấy giới hạn văn bản.

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
}

Bây giờ sử dụng nó dễ dàng như vậy: Để vẽ văn bản nhiều dòng:

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

Để đo văn bản:

val bound = yourPaint.getTextBoundMultiLine (văn bản)

Trong trường hợp này, nó sẽ đo tất cả văn bản từ đầu đến cuối và bằng cách sử dụng Rect mặc định được phân bổ (có thể thay đổi).
Bạn có thể chơi xung quanh với việc chuyển các tham số bổ sung để thêm linh hoạt.


-1

Ví dụ của tôi với Định cỡ và khoảng cách văn bản động, Hoạt động rất tốt cho tôi ...

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.