TextShaper


public class TextShaper
extends Object

java.lang.Object
   ↳ android.text.TextShaper


Provides text shaping for multi-styled text. Here is an example of animating text size and letter spacing for simple text.

 
 // In this example, shape the text once for start and end state, then animate between two shape
 // result without re-shaping in each frame.
 class SimpleAnimationView @JvmOverloads constructor(
         context: Context,
         attrs: AttributeSet? = null,
         defStyleAttr: Int = 0
 ) : View(context, attrs, defStyleAttr) {
     private val textDir = TextDirectionHeuristics.LOCALE
     private val text = "Hello, World."  // The text to be displayed

     // Class for keeping drawing parameters.
     data class DrawStyle(val textSize: Float, val alpha: Int)

     // The start and end text shaping result. This class will animate between these two.
     private val start = mutableListOf<Pair<PositionedGlyphs, DrawStyle>>()
     private val end = mutableListOf<Pair<PositionedGlyphs, DrawStyle>>()

     init {
         val startPaint = TextPaint().apply {
             alpha = 0 // Alpha only affect text drawing but not text shaping
             textSize = 36f // TextSize affect both text shaping and drawing.
             letterSpacing = 0f // Letter spacing only affect text shaping but not drawing.
         }

         val endPaint = TextPaint().apply {
             alpha = 255
             textSize =128f
             letterSpacing = 0.1f
         }

         TextShaper.shapeText(text, 0, text.length, textDir, startPaint) { _, _, glyphs, paint ->
             start.add(Pair(glyphs, DrawStyle(paint.textSize, paint.alpha)))
         }
         TextShaper.shapeText(text, 0, text.length, textDir, endPaint) { _, _, glyphs, paint ->
             end.add(Pair(glyphs, DrawStyle(paint.textSize, paint.alpha)))
         }
     }

     override fun onDraw(canvas: Canvas) {
         super.onDraw(canvas)

         // Set the baseline to the vertical center of the view.
         canvas.translate(0f, height / 2f)

         // Assume the number of PositionedGlyphs are the same. If different, you may want to
         // animate in a different way, e.g. cross fading.
         start.zip(end) { (startGlyphs, startDrawStyle), (endGlyphs, endDrawStyle) ->
             // Tween the style and set to paint.
             paint.textSize = lerp(startDrawStyle.textSize, endDrawStyle.textSize, progress)
             paint.alpha = lerp(startDrawStyle.alpha, endDrawStyle.alpha, progress)

             // Assume the number of glyphs are the same. If different, you may want to animate in
             // a different way, e.g. cross fading.
             require(startGlyphs.glyphCount() == endGlyphs.glyphCount())

             if (startGlyphs.glyphCount() == 0) return@zip