android canvas draw 3d letters
The Android Canvas offers a variety of drawing functions for implementing custom graphics in your app. A common utilize of Canvass is to draw text to a given region of a custom View, Drawable, Bitmap, etc.
Sheet has existing functions that allow you to draw text, the simplest of which tin can be seen below:
sheet.drawText(text, x, y, pigment) A single line of text is drawn at a given (x, y) origin, taking into account the properties of the Paint (to describe the colors and styles for the drawing eg. colour, textSize, etc.). Other variants of this function exist that permit for specification of get-go and terminate positions within the text, cartoon along a Path, etc.
The limitations of Canvass text drawing 🤨
The existing Canvas text drawing functions are simple and powerful but aren't without their limitations. The major drawback (as mentioned above) is that the text is drawn on a single line. If the width of the text exceeds the width of the Canvas, the text will be clipped. Long text will usually need to be drawn on multiple lines, and you lot may accept wanted "paragraph" style text in the first place. From here on, we'll refer to this as multiline text.
How do we depict multiline text? 🤔
So how should we become most implementing this? Unfortunately you tin't but include \north characters in your text, every bit all whitespace characters are interpreted and drawn as spaces within the unmarried line. Paint includes handy measureText and breakText functions for splitting up text which yous could use. You may fifty-fifty consider an existing algorithm such equally the Knuth-Plass Line Wrapping Algorithm. This quickly becomes a complex problem.
Android framework to the rescue 🚀
Thankfully, the Android framework provides us with a class that handles all of the complexity for us: Layout (in the android.text packet), described as "a base of operations class that manages text layout in visual elements on the screen". Information technology forms the footing of how classes like TextView fit text within given layout parameters.
The documentation stipulates:
For text that will be edited, utilize a
DynamicLayout, which will be updated as the text changes. For text that will not change, use aStaticLayout.
Considering that nosotros are trying to describe some static (multiline) text to Canvas, StaticLayout is just what we need!
Using StaticLayout 👨💻
Using StaticLayout is quite simple. Firstly, instantiate i by obtaining and using a StaticLayout.Architect:
val staticLayout = StaticLayout.Builder
.obtain(text, showtime, finish, textPaint, width)
.build() A few parameters are required when obtaining the builder:
-
text: The textCharSequenceto be laid out, optionally with spans -
start: The alphabetize of the start of the text -
end: The index + 1 of the stop of the text -
textPaint: TheTextPaintused for layout -
width: The bounding width (in pixels)
These parameters allow StaticLayout to layout the text appropriately within the bounding width. A resultant height belongings becomes available in one case the StaticLayout has been instantiated. Many other parameters can exist appended to the builder to adjust the terminate appearance, but we'll get to those subsequently.
Note: StaticLayout.Builder was added in API Level 23. Prior to this, you need to use the StaticLayout constructors. To add to this, the constructors have been deprecated in API Level 28. Be sure to handle backwards compatibility appropriately.
And so draw!
staticLayout.draw(canvas) Note: If you happen to be utilising this in the onDraw function of a custom View , be sure to instantiate the StaticLayout separately to avoid object resource allotment during drawing (in a constructor or Kotlin init block, for case).
A discussion on TextPaint ☝️
Before nosotros progress, there's ane thing that needs to be discussed… What is TextPaint? While almost all Canvas functions crave a Paint parameter, StaticLayout requires a TextPaint. From the documentation, it is described equally "an extension of Paint that leaves room for some extra information used during text measuring and drawing". A keen explanation tin be found here. In short, you lot apply it exactly as you would Pigment and don't accept to worry nigh the extra data information technology includes (for the purpose of what we are doing).
Exploring the StaticLayout properties 🔍
Phew! We at present know the basics of what StaticLayout is and how we can apply it to describe multiline text to Canvas. However, there are a lot of parameters that you can provide to change the appearance of the stop result.
Consider a basic text editor: you lot usually have options to change the alignment, margins, line spacing, text size and more. The aforementioned is truthful for StaticLayout; additional parameters tin can be appended to the StaticLayout.Builder.
It is important to note that some parameters (like colour) do not belong straight to StaticLayout, but rather belong to theTextPaint. Let'southward take a look at the some of the options we have:
alignment
The alignment of the text, like to gravity.
textDirection
The horizontal direction that the text follows.
lineSpacing
The spacing between lines of text (includes spacingMult and spacingAdd).
justificationMode (minSdk 26)
Options to justify the text (stretch spaces and so that the lines appear "square").
Other properties include ellipsize, maxLines, indents and more. Bank check the StaticLayout and StaticLayout.Builder documentation for what'due south available.
Positioning multiline text 📍
By default, calling staticLayout.draw(canvas) volition draw the unabridged block of text (from its top left corner) at position (0, 0) on the Sheet. This is fine for simple utilise cases, only we may want to position the text elsewhere (as we are able to do with the default Canvas text drawing methods).
We know that nosotros define the bounding width of this block, and that we get a resultant top once we've instantiated the StaticLayout. We tin can use these backdrop forth with a bones Canvas translation to position the text.
To do this, we declare a StaticLayout extension function. Information technology makes use of the handy Canvas.withTranslation part found in the Android KTX library:
fun StaticLayout.draw(sail: Canvas, x: Float, y: Float) {
sail.withTranslation(ten, y) {
draw(this)
}
} Using Kotlin to make it feel familiar 🤓
At that place may be multiple places in an app in which we need to implement multiline text drawing. Instantiating a StaticLayout in every identify would lead to unnecessary bloat. So let'southward brand an extension office for Canvas!
fun Canvas.drawMultilineText(
text: CharSequence,
textPaint: TextPaint,
width: Int,
x: Float,
y: Bladder,
beginning: Int = 0,
terminate: Int = text.length,
alignment: Layout.Alignment = Layout.Alignment.ALIGN_NORMAL,
textDir: TextDirectionHeuristic = TextDirectionHeuristics.LTR,
spacingMult: Float = 1f,
spacingAdd: Float = 0f,
hyphenationFrequency: Int = Layout.HYPHENATION_FREQUENCY_NONE,
justificationMode: Int = Layout.JUSTIFICATION_MODE_NONE) { val staticLayout = StaticLayout.Architect
.obtain(text, start, cease, textPaint, width)
.setAlignment(alignment)
.setTextDirection(textDir)
.setLineSpacing(spacingAdd, spacingMult)
.setBreakStrategy(breakStrategy)
.setJustificationMode(justificationMode)
.build()
staticLayout.draw(this, x, y)
}
This extension function includes most (not all) of the StaticLayout properties, and provides default values for those that may non be used as usually. It likewise makes utilise of our previously defined extension function to position the block of text.
Nosotros can now describe multiline text to Sheet in a way that feels very familiar to the existing text drawing functions:
canvas.drawMultilineText(text, textPaint, width, 10, y) But at that place'south 1 issue… 😬
Our new drawMultilineText extension function is bully to use, but it's doing something it shouldn't: information technology instantiates a new StaticLayout every fourth dimension information technology is called. This violates our goal to avoid object allocation during drawing.
Implementing a StaticLayout cache 💾
There's nearly probable a variety of ways to solve the same upshot. One approach is to implement a basic LruCache to store/retrieve StaticLayouts for drawing (again making use of the Android KTX library for the lruCache extension function):
object StaticLayoutCache { individual const val MAX_SIZE = 50 // Max number of cached items
private val enshroud = lruCache<String, StaticLayout>(MAX_SIZE)
operator fun set(key: String, staticLayout: StaticLayout) {
cache.put(key, staticLayout)
}
operator fun get(cardinal: String): StaticLayout? {
return cache[key]
}
}
Now, nosotros only instantiate a StaticLayout on first use of the drawMultilineText part (and put it in the enshroud), otherwise nosotros get one from the enshroud:
val staticLayout = StaticLayoutCache[cacheKey] ?:
StaticLayout.Architect.obtain(text, get-go, end, textPaint, width)
... // Add other properties
.build().apply { StaticLayoutCache[cacheKey] = this } The final slice of the puzzle is deciding what to use as the cacheKey. Using StaticLayout.toString() comes to mind, only this means nosotros would need to instantiate it first, which nosotros don't desire to exercise if there'south a cached version. Given that the parameters of the drawMultilineText function essentially describe the uniqueness of a StaticLayout for our purposes, we tin create our own key like so:
val cacheKey = "$text-$start-$end-$textPaint-$width-$alignment-$textDir-$spacingMult-$spacingAdd-$breakStrategy-$justificationMode" Wrapping information technology upwards 🎁
The final implementation provides u.s. with an idiomatic (and, hopefully, performant) mode of cartoon multiline text to Canvass, which feels at habitation among other Canvas functions. It also includes full backwards compatibility and all of the available StaticLayout properties. Using Kotlin extension functions, named parameters and operator overloading has greatly reduced the amount of code and made the finish result easier to use.
I hope this post has provided some insight into StaticLayout and how it tin can be used for multiline text drawing on Canvas. If you lot have any questions, thoughts or suggestions so I'd honey to hear from you!
Find me on Twitter @ricknout
reginanerisfamands54.blogspot.com
Source: https://medium.com/over-engineering/drawing-multiline-text-to-canvas-on-android-9b98f0bfa16a
Post a Comment for "android canvas draw 3d letters"