Android Code Snippet [B4X] [XUI] Accurate Text Measurement and Drawing

(It took me 7 years to get this one right.)

text.gif



SS-2018-05-09_13.04.52.png


SS-2018-05-09_13.05.38.png


XUI v1.60 includes a new method named B4XCanvas.MeasureText. This method accurately measures single line strings.
It returns a B4XRect object with the width and height of the measured string. The Top field returns the highest point relative to the baseline.

With these values it is possible to accurately vertically center the text with this code (works in all three platforms):
B4X:
Dim r As B4XRect = cvs1.MeasureText(Text, Fnt)
Dim BaseLine As Int = CenterY - r.Height / 2 - r.Top
cvs1.DrawText(Text, CenterX, BaseLine, Fnt, Clr, "CENTER")

Sub that also draws the border and the baseline:
B4X:
Sub DrawTextWithBorder (cvs1 As B4XCanvas, Text As String, Fnt As B4XFont, Clr As Int, CenterX As Int, CenterY As Int)
   Dim r As B4XRect = cvs1.MeasureText(Text, Fnt)
   Dim BaseLine As Double = CenterY - r.Height / 2 - r.Top
   cvs1.DrawText(Text, CenterX, BaseLine, Fnt, Clr, "CENTER")
   cvs1.DrawCircle(CenterX, CenterY, 3dip, xui.Color_Blue, True, 0)
   r.Initialize(CenterX - r.Width / 2, CenterY - r.Height / 2, CenterX + r.Width / 2, CenterY + r.Height / 2)
   cvs1.DrawLine(r.Left, BaseLine, r.Right, BaseLine, xui.Color_Gray, 1dip)
   cvs1.DrawRect(r, xui.Color_Gray, False, 2dip)
End Sub

Note that in B4i there was a small change in the way the offsets are set internally in B4XCanvas.DrawText.

The XUI libraries are internal libraries. iXUI v1.60 and jXUI v1.60 will be included in the next versions of B4i and B4J. B4A XUI 1.60: https://www.b4x.com/android/forum/threads/updates-to-internal-libraries.59340/#post-587118
 
Last edited:
D

Deleted member 103

Guest
(It took me 7 years to get this one right.)
Then you have been too slow. :D

Thank you Erel! You never stop bringing something new. :)
 

KMatle

Expert
Licensed User
Longtime User
Since two years I'm good with using the known methods. What makes wonder is the object's/method's name "B4XCanvas.MeasureText".

Here a canvas is used to measure a text. I would have done it (if I was Google) like "Textobject.NeededWidth" or "Textobject.NeededHeight" depending on the content and given textsize or even vice versa "Textobject.MaxTextsizeToFit" when you set the height and width.

Strange that Google did not implement such a basic thing.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Since two years I'm good with using the known methods.
Note that it is not possible to accurately draw a border around text, like done in this example, with the standard Canvas.MeasureStringHeight method as it only returns the total height and lacks the height above baseline.

What makes wonder is the object's/method's name "B4XCanvas.MeasureText".
This is a good point. In B4J and B4i you can call this method without initializing the B4XCanvas object as the internal canvas features are not needed. In B4A you do need to initialize it however you can create a 1x1 pixel canvas and use it for all measurements.
 

ivan.tellez

Active Member
Licensed User
Longtime User
Thanks, that was just on Time @Erel

I started to update an App after 2 years. Actually was really easy to draw Accurate text with AcceleratedSurface, but now I want limit the use of Libs to make the iOS version.

I was about to drop XUI for the lack of text measurement. Are you also going to add DrawRoundRect ?
 
Top