Android Question Max Text Size

RandomCoder

Well-Known Member
Licensed User
Longtime User
Had to go to bed not getting this to work and what's wrong is still evading me this morning :mad:

Basically I would like to set the largest text size possible for Labels and Textbox's. But the views are not created in the designer and so I cannot let the designer and AutoScale take care of it. I've seen an example using StringUtils but was hoping to do this with just core functions. It dawned on me that the problem might be to do with padding around the text and for this I've used JavaObject.
This fixed getting the text to display correctly in portrait mode but it is still too large when in landscape. It seems that if the height of the view is larger than the width then it works correctly but if smaller then the textsize is too large even though the canvas MeasureStringHeight suggests that it should fit?
I've thrown together a small sample (attached), and the code I'm using is shown below.

B4X:
Private Sub maxTextSize(v As View, str As String) As Float
    ' Get padding values
    Dim jo As JavaObject = v
    Dim intPaddingLR As Int= jo.Runmethod("getPaddingLeft",Null) + jo.Runmethod("getPaddingRight",Null)
    Dim intPaddingTB As Int = jo.Runmethod("getPaddingTop",Null) + jo.Runmethod("getPaddingBottom",Null)
    ' Set canvas and initialise text size to try
    Dim c As Canvas
    c.Initialize(v)
    Dim fltSize As Float = 70
    Dim fltW As Float = c.MeasureStringWidth(str, Typeface.DEFAULT_BOLD, fltSize)
    Dim fltH As Float = c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fltSize)
    ' Check if text size will fit, continue reducing until it fits.
    Do While (fltW > (v.Width - intPaddingLR)) OR (fltH > (v.Height - intPaddingTB))
        fltSize = fltSize - 2
        fltW = c.MeasureStringWidth(str, Typeface.DEFAULT_BOLD, fltSize)
        fltH = c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fltSize)
        Log(fltW & " (" & (v.Width - intPaddingLR) & ") " & fltH & " (" & (v.Height - intPaddingTB) & ")")
    Loop
    Log("Size " & fltSize)
    Return fltSize
End Sub
 

Attachments

  • BigText.zip
    11.7 KB · Views: 401

RandomCoder

Well-Known Member
Licensed User
Longtime User
I've placed several more log statements in the code and I believe that this line is the root cause of my problem...
B4X:
c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fltSize)
It is giving back the wrong value for the actual string height, as the canvas size and the padding values seem to be reporting they're size correctly when checked against the Label and Textbox height.

I was hoping not to have to use Reflection and StringUtils as I'm creating a class which I'm trying to keep small in size, if the canvas will do all that I need then this is the preferred option for me. Is it possible that MeasureStringHeight is giving back the wrong value?
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
You need to take into account the device scale, and divide the measured value by it. You are measuring pixels, while the font size is measured in DPI I think... You can check in my "set text size" sub's in the on going project
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
You need to take into account the device scale, and divide the measured value by it. You are measuring pixels, while the font size is measured in DPI I think... You can check in my "set text size" sub's in the on going project
I'm not sure that is the problem as it works perfect when the view is higher than it is wide. I've found that if I multiply the measured string height by 1.75 it then works. I might just leave it like that.
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
I'll try and test on some other devices to see if I can use a fixed multiplier or if I need to take into account the device scale!
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
I use a fixed multiplier, and haven't had any issues until now...
 
Upvote 0

ivanomonti

Expert
Licensed User
Longtime User
the result is quite good , I had to change to the bottom subtracting 4dip , just for a app that loads data like mine , the process becomes long , despite having a good level of device ( lg - flex )

11350319_910584355672338_1831922682_n.jpg
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
.... just for a app that loads data like mine , the process becomes long , despite having a good level of device ( lg - flex )
Try changing the starting value from 70 to a value closer to what you expect to need, then it won't loop as many times to find the largest text size.
B4X:
Dim fltSize As Float = 70
I've also had to modify the MeasureStringHeight lines by multiplying the value by 1.75 to ensure it fits the text if the view is wider than it is tall...
B4X:
From this...
fltH As Float = c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fltSize)

To this...
fltH As Float = c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fltSize)*1.75
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
It dawned on me that the problem might be to do with padding around the text and for this I've used JavaObject.


B4X:
Private Sub maxTextSize(v As View, str As String) As Float
    ' Get padding values
    Dim jo As JavaObject = v
    Dim intPaddingLR As Int= jo.Runmethod("getPaddingLeft",Null) + jo.Runmethod("getPaddingRight",Null)
    Dim intPaddingTB As Int = jo.Runmethod("getPaddingTop",Null) + jo.Runmethod("getPaddingBottom",Null)
    ' Set canvas and initialise text size to try
    Dim c As Canvas
    c.Initialize(v)
    Dim fltSize As Float = 70
    Dim fltW As Float = c.MeasureStringWidth(str, Typeface.DEFAULT_BOLD, fltSize)
    Dim fltH As Float = c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fltSize)
    ' Check if text size will fit, continue reducing until it fits.
    Do While (fltW > (v.Width - intPaddingLR)) OR (fltH > (v.Height - intPaddingTB))
        fltSize = fltSize - 2
        fltW = c.MeasureStringWidth(str, Typeface.DEFAULT_BOLD, fltSize)
        fltH = c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fltSize)
        Log(fltW & " (" & (v.Width - intPaddingLR) & ") " & fltH & " (" & (v.Height - intPaddingTB) & ")")
    Loop
    Log("Size " & fltSize)
    Return fltSize
End Sub


Do you get any values out of the "getPadding" methods? I basically copied a couple of lines from your example to get the padding but I'm always getting zero!
My idea to get it perfect is to measure a fixed String like "tgjB" and then subtract the padding and divide the result by the density factor... But my font size is always a bit too big because the padding value is incorrect.
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
The padding on Labels is normally zero, whereas the padding on a Textbox seems to be fixed at 48 horizontal (24 left and right) and 30 vertical (15 top and bottom).
I've just run a quick test and it seems that these padding values are fixed irrespective of the size of the Textbox.
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
Hi @klaus there are no layout parameters. The point I was trying to make was that I was creating the views in code not the designer (see post #1). If the view is wider than it is tall then all works correctly using Canvas.MeasureStringWidth but if the view is taller than it is wide then the text is sized incorrectly because Canvas.MeasureStringHeight is incorrectly reporting the expected height of the text. At least that is my feeble understanding of the problem. Erel has explained to me that in this case the correct method is to use StringUtils and Reflection libs as this uses a slightly different approach based on a higher api.
It's now 02:30 in the morning and I've had several beers after attending a wedding reception so I'm going that all makes sense :D
 
Upvote 0
Top