Bug? canvas.MeasureStringWidth return wrong value

ArminKH

Well-Known Member
hi erel
i think some times canvas return wrong values for MeasureStringWidth
i think when the text completely is fit in a view,then the width of text must be less or equal to width of view.is this wrong?
and if not please test attached sample

if every thing is right on your device please see attached screen shot(Tested on android 4.2.1 With 5" screen and density 1.5)

is there any way to measure string width by using reflection or other tools?
tnx erel
 

Attachments

  • CanvasExample.zip
    7.9 KB · Views: 319
  • 2015_02_10_04.28.23.png
    2015_02_10_04.28.23.png
    50.9 KB · Views: 488

ArminKH

Well-Known Member
and in addition canvas can't measure the width of Tab in a text :)
good night
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Canvas.MeasureStringWidth calls the native Paint.measureText method to measure the width.

After I removed the following line:
Label1.Width=Label1.Width-1dip
I see a difference of less than 1dip between the two results. It seems like a rounding error as suggested by the link @stevel05 posted.

Note that you can use the AutoTextSizeLabel to accomplish a similar solution.
 

ArminKH

Well-Known Member
Canvas.MeasureStringWidth calls the native Paint.measureText method to measure the width.

After I removed the following line:
Label1.Width=Label1.Width-1dip
I see a difference of less than 1dip between the two results. It seems like a rounding error as suggested by the link @stevel05 posted.

Note that you can use the AutoTextSizeLabel to accomplish a similar solution.
Please see my attached screenshot in post 1
The difference is more than 1 or 2
After i remove that part of code,the difference is 4 between text width and label width !
In addition the above code is necessary 4 last loop because my label width is increasing while my line count is > one and in last loop label1.width=label1.width+1dip and is a bit more than text width,so i reduce it by -1dip
why u delete it?
Erel when i set label1.width to -2 and measure width by using getWidth method in java object every thing is right but i dont want to use this
has label1.width=-2 equal in java????any method for return same value
 
Last edited:

ArminKH

Well-Known Member
@stevel05
tnx 4 your response
My english is not good
i use getTextBound method by javaobject but b4a said this method not found
Excuse me i'm not familar with java
Can u please edit my code by above solution?
just I want know width of text without any additional thing
 

stevel05

Expert
Licensed User
Longtime User
The B4j code cannot be used in Android as it relies on JavaFX methods and objects.

Measuring text without displaying it in Android is problematic, the only method I have found that works consistently is using the Canvas Measure text. If you've found a more accurate method I suggest you use that, and hide the view used to measure the string off the edge of the screen.

As you've asked for it, here is some code to use the getTextBounds method of paint.

B4X:
Dim Paint As JavaObject
        Dim Bounds As Rect
        Bounds.Initialize(0,0,0,0)
        Paint.InitializeNewInstance("android.graphics.Paint",Null)
        Paint.RunMethod("setTextSize",Array(Label1.TextSize))
        Paint.RunMethod("setTypeface",Array(Label1.Typeface))
        Paint.RunMethod("getTextBounds",Array(Label1.Text,0,Label1.Text.Length,Bounds))
       
        Dim r As Reflector
           r.Target = r.GetContext
           r.Target = r.RunMethod("getResources")
           r.Target = r.RunMethod("getDisplayMetrics")
           Log(r.GetField("xdpi"))
           Log(r.GetField("ydpi"))
        Log(Bounds.Left)
        Log((Bounds.Right - Bounds.Left)* (r.GetField("xdpi")/ 160))
       
        Dim PFM As JavaObject = Paint.RunMethod("getFontMetrics",Null)
        Log(PFM.GetField("leading"))
 
Last edited:

ArminKH

Well-Known Member
The B4j code cannot be used in Android as it relies on JavaFX methods and objects.

Measuring text without displaying it in Android is problematic, the only method I have found that works consistently is using the Canvas Measure text. If you've found a more accurate method I suggest you use that, and hide the view used to measure the string off the edge of the screen.

As you've asked for it, here is some code to use the gettextbounds method of Paint. Testing on Genymotion gave an even bigger value for the text length.

B4X:
Dim Paint As JavaObject
        Dim Bounds As Rect
        Bounds.Initialize(0,0,0,0)
        Paint.InitializeNewInstance("android.graphics.Paint",Null)
        Paint.RunMethod("setTextSize",Array(Label1.TextSize))
        Paint.RunMethod("setTypeface",Array(Label1.Typeface))
        Paint.RunMethod("getTextBounds",Array(Label1.Text,0,Label1.Text.Length,Bounds))
     
        Dim r As Reflector
        r.Target = r.GetContext
        r.Target = r.RunMethod("getResources")
        r.Target = r.RunMethod("getDisplayMetrics")
        Log(r.GetField("xdpi"))
        Log(r.GetField("ydpi"))
        Log((Bounds.Right - Bounds.Left)* r.GetField("xdpi")/ 160)
     
        Dim PFM As JavaObject = Paint.RunMethod("getFontMetrics",Null)
        Log(PFM.GetField("leading"))

Relevent documentation is here: http://developer.android.com/reference/android/graphics/Paint.html


ok tnx :)
when an issue solved new problem appared.
but thank u mr stevel your answer every time is complete and helpful and i think u are my teacher and i can every time learn new thing from your knowledge
excuse me 4 my english
best regard
 
Top