Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Dibujar texto de varias líneas en Lienzo

Una pregunta que espero que sea rápida, pero no puedo encontrar ningún ejemplo … Me gustaría escribir texto de varias líneas a una View personalizada a través de un Canvas , y en onDraw() Tengo:

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

Esperaba que esto resultara en saltos de línea, pero en cambio estoy viendo caracteres crípticos donde \n estaría.

Cualquier puntuación apreciada.

Pablo

  • DrawBitmap con diferentes salidas de renderizado (Nexus 7 versus otros dispositivos)
  • Cómo obtener Bitmap de WebView genera un fallo de OutOfMemory
  • Android View.onDraw () siempre tiene un lienzo limpio
  • Cómo dibujar imágenes de puntos en el borde del círculo de la imagen
  • Línea de dibujo de lienzo de Android - hacer la línea más gruesa
  • Trabaje alrededor de Canvas.clipPath () que ya no es compatible con android
  • Dibuja una línea con bordes curvos en Android
  • Canvas Cambia dinámicamente el índice z de un mapa de bits
  • 12 Solutions collect form web for “Dibujar texto de varias líneas en Lienzo”

    Lamentablemente, Android no sabe qué es \n . Lo que tienes que hacer es quitar el \n luego compensar el Y para obtener el texto en la siguiente línea. Así que algo como esto:

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

    Encontré otra forma de usar diseños estáticos. El código está aquí para que cualquiera pueda referirse a:

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

    Simplemente iterar a través de cada línea:

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

    Esta es mi solución que se basa en la respuesta @ Dave (gracias 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(); } } } 

    Intenté heredar Canvas, pero en realidad no te lo permite. Así que esta es una clase intermedia!

    Tengo que añadir aquí mi versión que considera la anchura del CURSO también.

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

    Sí. Utilice canvas.getFontSpacing() como el incremento. Lo he probado por curiosidad y funciona para cualquier fuente.

    He escrito ejemplo completo

    Introduzca aquí la descripción de la imagen

    Colors.xml

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

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

    He reutilizado la solución propuesta por GreenBee y he hecho una función para dibujar un texto de varias líneas en los límites especificados con el "…" al final si ocurrió un truncado:

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

    prueba esto

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

    funcionará. probé

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

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

    Solución sin 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; } } } } } 

    Mi ejemplo con tamaño de texto dinámico y el espaciado, funciona muy bien para mí …

     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; } 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.