Cómo dibujar una cadena Spanned con Canvas.drawText en Android

Quiero dibujar un SpannedString a un Canvas .

Introduzca aquí la descripción de la imagen

 SpannableString spannableString = new SpannableString("Hello World!"); ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED); BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW); spannableString.setSpan(foregroundSpan, 1, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannableString.setSpan(backgroundSpan, 3, spannableString.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(spannableString); 

El ejemplo anterior se ha dibujado utilizando un TextView , que a su vez utiliza un Layout para dibujar texto con spans. Sé que el uso de un Layout es la forma recomendada para dibujar texto en el lienzo. Sin embargo, estoy haciendo mi propia disposición del texto del rasguño, así que necesito implementar esto mismo.

Hacer algo como esto no funciona

 canvas.drawText(spannableString, 0, spannableString.length(), 0, 0, mTextPaint); 

Porque drawText sólo obtiene el texto del spannableString , no cualquiera de los spannableString . Los colores de dibujo son manejados por separado por TextPaint .

¿Cómo utilizo canvas.drawText (o drawTextRun ) para dibujar la información del intervalo (específicamente el primer plano y el color de fondo aquí)?

Relacionado

  • Cómo realizar un bucle a través de las extensiones en una SpannedString o SpannableString en Android
  • ¿Es posible mostrar texto multicolor con una llamada a Canvas.drawText ()?

Planificar una solución

Iba a hacer directamente una auto-respuesta, pero esto está resultando ser más difícil de lo que pensaba. Así que voy a publicar primero y luego agregar una respuesta cada vez que pueda averiguarlo. (Por supuesto, daría la bienvenida a cualquiera para responder primero.)

Aquí están las piezas que tengo hasta ahora:

  • Dibuje cada rango de span como una secuencia de texto independiente
  • Use drawTextRun para dibujar el texto ( ejemplos ) ( actualización : no se agrega hasta API 23)
  • Use getRunAdvance para medir dónde comenzar la siguiente ejecución de texto ( actualización : no se agrega hasta API 23, use measureText en measureText lugar)
  • El color de fondo probablemente tendrá que ser dibujado por separado (con drawRect o quizás drawPath ? Vea aquí , aquí y aquí .)
  • Código fuente para TextView , StaticLayout y TextLine

One Solution collect form web for “Cómo dibujar una cadena Spanned con Canvas.drawText en Android”

Para la mayoría de la gente que viene a esta pregunta, probablemente debería usar un StaticLayout para dibujar su texto StaticLayout . Vea esta respuesta para ayudar con eso.

Sin embargo, si realmente necesita dibujar el texto dividido usted mismo, entonces necesitará recorrer todos los rangos extendidos y dibujar cada uno por separado. También es necesario medir la longitud del texto en cada tramo para que sepa dónde empezar a dibujar el siguiente tramo.

El código siguiente maneja BackgroundColorSpan y ForegroundColorSpan .

 // set up the spanned string SpannableString spannableString = new SpannableString("Hello World!"); ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED); BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW); spannableString.setSpan(foregroundSpan, 1, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannableString.setSpan(backgroundSpan, 3, spannableString.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // draw each span one at a time int next; float xStart = 0; float xEnd; for (int i = 0; i < spannableString.length(); i = next) { // find the next span transition next = spannableString.nextSpanTransition(i, spannableString.length(), CharacterStyle.class); // measure the length of the span xEnd = xStart + mTextPaint.measureText(spannableString, i, next); // draw the highlight (background color) first BackgroundColorSpan[] bgSpans = spannableString.getSpans(i, next, BackgroundColorSpan.class); if (bgSpans.length > 0) { mHighlightPaint.setColor(bgSpans[0].getBackgroundColor()); canvas.drawRect(xStart, mTextPaint.getFontMetrics().top, xEnd, mTextPaint.getFontMetrics().bottom, mHighlightPaint); } // draw the text with an optional foreground color ForegroundColorSpan[] fgSpans = spannableString.getSpans(i, next, ForegroundColorSpan.class); if (fgSpans.length > 0) { int saveColor = mTextPaint.getColor(); mTextPaint.setColor(fgSpans[0].getForegroundColor()); canvas.drawText(spannableString, i, next, xStart, 0, mTextPaint); mTextPaint.setColor(saveColor); } else { canvas.drawText(spannableString, i, next, xStart, 0, mTextPaint); } xStart = xEnd; } 

La cadena superior en la imagen de abajo se dibujó con el código anterior. La cadena inferior se dibujó con un TextView regular (que utiliza un StaticLayout ).

Introduzca aquí la descripción de la imagen

  • Combinación de Spannable con String.format ()
  • Android SpannableString establecer fondo detrás de parte del texto
  • Handle hace clic en los vínculos de TextView mientras utiliza Linkify para encontrar y establecer los vínculos dentro del texto
  • mostrar emoticonos con Spannable en una vista de texto
  • ¿Cómo hacer clic o tocar en un texto TextView en diferentes palabras?
  • Cómo aplicar la viñeta y la lista numerada en android Edit-text
  • Android: ¿Cómo combinar Spannable.setSpan con String.format?
  • Cómo obtener el ancho del texto cuando el ajuste de varios spannable
  • En un EditText, ¿hay una manera de desactivar la autocorrección en un span?
  • Android Development: Cómo reemplazar parte de un EditText con un Spannable
  • SpannableString: ¿Es posible aplicar dos o más RelativeSizeSpans?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.