Android Question Canvas.DrawText Positioning issue/formula

Discussion in 'Android Questions' started by Cableguy, Jun 22, 2015.

Similar threads

B4A Library Printing and Pdf creation
B4A Code Snippet Animated Border
B4A Code Snippet Color Picker
B4A Tutorial [B4X] [XUI] Drawing with B4XCanvas
B4A Code Snippet Draw round bitmap
  1. Cableguy

    Cableguy Expert Licensed User

    Hi Guys

    I'm trying to place a single character dead center on a label using canvas and drawtext.
    The issue is, even thou I have set the padding to zero on all four sides, I still get my character a bit off-centre vertically. Horizontal Center is easy to get, as we just set the draw text alignment to "CENTER", but to center it vertically is proving challenging to say the least...
    so any help would be very welcomed!!

    what I got that "almost" works...

    Code:
    Sub SetlabelText(v As Label, TFace As Typeface, txt As String)
        SetPadding(v, 
    0000' we set the padding
       
        
    Private vHeight As Int = v.Height ' the view's Height
        Private vWidth As Int = v.Width ' the view's Width
        Private tBase As Int ' the Text Base value
       
        
    If vHeight > vWidth Then 'if it's taller than it is wide
            tBase = vWidth ' the text size is calculated relatively to the view's Width
        Else 'if it's wider than it is tall
            tBase = vHeight ' the text size is calculated relatively to the view's Height
        End If
       
        
    'Now we get the max FontSize possible for tBase
        Private CV As Canvas
        CV.Initialize(v)
        
    Private x As Int = 0
        
    Do Until CV.MeasureStringHeight("+", TFace, x)>= tBase
            x=x+
    1
        
    Loop
       
        
    ' I want it to be about 70% of tBase
        x = Floor(x * 0.7)
       
        
    'Now I get the final sizes for text height with the calculated font size
        Private tHeight As Int = CV.MeasureStringHeight(txt, TFace, x)

        
    'and try to calculate the vertical origin point (x?) for the string
        Private yBase As Int = Floor (vHeight - ((vHeight-tHeight)/2)) ' wich clearly eludes me!!!!
        Private xBase As Int = Floor(vWidth/2)'this is horizontal origin point, center!

        CV.DrawText(txt,xBase, yBase, TFace, x, 
    Colors.Black, "CENTER")     
    End Sub
    This should be as easy as subtracting the text height from the view's height, and divide that by two... then subtract that value from the views height, right???? apparently not, so... Please Help!!!
     
  2. RandomCoder

    RandomCoder Well-Known Member Licensed User

    I'm pretty sure that the problem will be with the Canvas.MeasureStringHeight it is not reliable. Erel advised me in a previous post somewhere on the Forum to use StringUtils instead.
     
  3. Cableguy

    Cableguy Expert Licensed User

    I'll try that, thanks for the heads up
     
  4. LucaMs

    LucaMs Expert Licensed User

    I would try using Float variables (DrawText requires Float) and changing:

    Code:
    Private yBase As Int = Floor (vHeight - ((vHeight-tHeight)/2))
    to:
    Code:
    Private yBase As Float = (vHeight - tHeight) / 2
     
  5. Cableguy

    Cableguy Expert Licensed User

    I'm about to blow a fuse!!!!!

    This should be so dead simple!!!
    All I what to accomplish is to place a single character dead center on a label, set to the max fontsize possible within the bounderies of the label.
    I have been trying to do it with a canvas and stringutils but it just never gets dead center!!!

    since the characters I want to draw are the plus and minus signs, would I be better of drawing them myself instead of using a font????

    Can the Math and view gurus give me a hand here???
     
  6. strat

    strat Active Member Licensed User

    This code write a text at center of an image. Reflector lib is required. It can be modified for another object like label, button.. etc



    Code:
    Sub Button1_Click
        
    Dim iv As ImageView
        
    Dim c As Canvas
        
    Dim rect1 As Rect
        
    Dim tf As Typeface
        
    Dim rx1,ry1,rw,rh As Int
        
    Dim r_,g_,b_,clr As Int
        
    Dim Height_, Width_,fs As Int
        
    Dim lbl As Label
        
    Dim obj As Reflector
        fs=
    23 ' Font size
        tf=Typeface.DEFAULT
        lbl.Initialize(
    "lbl")
        
    Activity.AddView(lbl,0,0,1,1)
        lbl.Typeface=tf
        lbl.TextSize=fs
        lbl.Text=
    Rnd(1,99)
        lbl.Width=-
    2
        lbl.Height=-
    2
        
    DoEvents
        obj.Target = lbl
        Width_ = obj.RunMethod(
    "getWidth")
        Height_ = obj.RunMethod(
    "getHeight")
      
        iv.Initialize(
    "iv")
        rx1=
    Rnd(0,90%x)
        ry1=
    Rnd(0,80%y)
        rw=
    10%x
        rh=
    10%x
        r_=
    Rnd(0,255)
        g_=
    Rnd(0,255)
        b_=
    Rnd(0,255)
      
        
    Activity.AddView(iv,rx1,ry1,rw,rh)
        c.Initialize(iv)
      
        rect1.Initialize(
    0,0,rw,rh)
      
        c.DrawOval(rect1,
    Colors.RGB(r_,g_,b_),True,5dip)
        c.DrawText(lbl.Text,(rw-Width_)/
    2,(rh+fs)/2,tf,fs, Colors.Black,"LEFT")
    End Sub
     
  7. Cableguy

    Cableguy Expert Licensed User

    Thanks @strat, but if I read correctly your code, You're using a "fixed" FontSize, right?
     
  8. LucaMs

    LucaMs Expert Licensed User

    Have you tried #4?
     
  9. strat

    strat Active Member Licensed User

    Yes font size is fix. Font size determination is another problem.
     
  10. Cableguy

    Cableguy Expert Licensed User

    yes I have, either there is still some reminiscent bottom padding, or the Font it self has extra lines...

    I haven't given up, but I'm done for today... I need a clearer head for this!
     
  11. RandomCoder

    RandomCoder Well-Known Member Licensed User

    Hi @Cableguy

    It looks like you've hit on the same problem I had a while ago when trying to do the same thing... Max Text Size. Here's the original post in which Erel stated that Canvas.MeasureString is based on an lower API and he recommended to use StringUtils instead... fontsize multiple layout.
    Another option is to use either the AutoTextSizeLabel Library which Erel has created... [custom view] AutoTextSizeLabel or apply a better scaling algorithm... Designer Scripts & AutoScale Tutorial

    Alternatively you can ignore all the good advice and use Canvas.MeasureString with a fixed multiplier as I have (sorry Erel :D), the AutoScale tutorial just looked over complex compared with a fixed multiplier applied to the result from Canvas.MeasureString. How far out can it be??
    Here's the code I use...
    Code:
    Private Sub getMaxTextSize(v As View, str As StringAs Float
        
    ' Get internal padding used by the view
        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 initial fontsize and get font dimensions
        Dim c As Canvas
        c.Initialize(v)
        
    Dim fpSize As Float = 70
        
    Dim fpW As Float = c.MeasureStringWidth(str, Typeface.DEFAULT_BOLD, fpSize) * 1.25
        
    Dim fpH As Float = c.MeasureStringHeight(str, Typeface.DEFAULT_BOLD, fpSize) * 1.75
        
    ' Check font dimensions and reduce font size until a fit is found
        Do While (fpW > (v.Width - intPaddingLR)) Or (fpH > (v.Height - intPaddingTB))
            fpSize = fpSize - 
    2
            fpW = c.MeasureStringWidth(str, 
    Typeface.DEFAULT_BOLD, fpSize) * 1.25
            fpH = c.MeasureStringHeight(str, 
    Typeface.DEFAULT_BOLD, fpSize) * 1.75
            
    ' Prevent possibility of getting stuck in the loop
            If fpSize < 2 Then Exit
        
    Loop
        
    Return fpSize
    End Sub
    And called using...
    Code:
    btnRGB_Up.TextSize   = getMaxTextSize(btnRGB_Up, "##")
    btnRGB_Up.Text       = 
    "+"
    In the example above I'm actually sending two characters "##" and then only applying a "+" and therefore the size is slightly smaller than the largest size possible but this was because for some reason the text starts to move away from MiddleCenter if made too large. I don't know why and this was my little work around ;)
     
    lemonisdead likes this.
  12. Peter Simpson

    Peter Simpson Well-Known Member Licensed User

    Have you tried mixing AutoTextSizeLabel with "Lbl.Gravity = Bit.Or(Gravity.CENTER_HORIZONTAL, Gravity.CENTER_VERTICAL)"
     
  13. Cableguy

    Cableguy Expert Licensed User

    I tried gravity.Center_vertical+gravity.Center_horizontal... Seems I used the wrong syntax... I will have a go at it later on
     
  14. sorex

    sorex Expert Licensed User

    it's the same and equals to CENTER
     
    RandomCoder likes this.
  15. Peter Simpson

    Peter Simpson Well-Known Member Licensed User

    When I was typing I completely forgot about Gravity.CENTER @sorex, but it is exactly the same. I just automatically type the above line whenever I need it. I need a nice cold Budweiser...
     
    RandomCoder likes this.
  16. sorex

    sorex Expert Licensed User

    I checked this and in my case it works as espected.

    the block at the bottom is what is being cut out at the top.
    there's a flu alpha pixel between the pixel & block below so it's perfectly even.

    Code:
    Dim l As Label
    l.Initialize(
    "")
    l.Text=
    "+"
    l.Color=
    Colors.Red
    l.TextColor=
    Colors.Black
    l.Gravity=
    Gravity.CENTER
    Activity.AddView(l,0,0,100,100)
     

    Attached Files:

    Cableguy likes this.
  17. Cableguy

    Cableguy Expert Licensed User

    Correct me if i'm wrong (most surtenly), but what I'm trying to accomplish should be as easy as setting the padding to zero, find the required max font size, and set the gravity to Center... Right???
    Seems not... But why!?
     
  18. sorex

    sorex Expert Licensed User

    ok, my bad. I just see that you want to draw it.

    I wonder why you want to draw it instead of using the normal methods?
    you don't have a font file of that bitmap font?
     
  19. Cableguy

    Cableguy Expert Licensed User

    I went with drawing before I discovered padding and how to set it... Then it just stayed there...
    I sometimes miss the forest because of all those dahm trees in front of it!
    I will try a less complex approach to it and see how it goes
     
  20. RandomCoder

    RandomCoder Well-Known Member Licensed User

    From experience trying to do exactly what CableGuy is doing, he unable to use the normal method i.e. set the font size and then the gravity because he does not know what font size is required. Therefore he must use a method to determine the required size after which he can apply it using the 'normal' method.

    The problem is in determining what is the largest possible text size that will fit a certain size of view.
     
Loading...