Android Question [Solved by Klaus] 9 patch height

LucaMs

Expert
Licensed User
I ran tests on some 9 patches I made and also using one found here on site (the one in the attached project) but in all my tests the height of the view is wrong.

Where am I wrong?
 

Attachments

Last edited:

LucaMs

Expert
Licensed User
Found right now this one on web... it works worse, although in the tool it looks ok.

ninepatch_bubble.9.png
 

Erel

Administrator
Staff member
Licensed User
You can draw it yourself:



Tested in B4J:
B4X:
Sub Process_Globals
   Private MainForm As Form
   Private ImageView1 As ImageView
   Private xui As XUI
   Private ImageView2 As ImageView
   Private ImageView3 As ImageView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   MainForm = Form1
   MainForm.RootPane.LoadLayout("1") 'Load the layout file.
   MainForm.Show
   CreateComicBalloon(ImageView1)
   CreateComicBalloon(ImageView2)
   CreateComicBalloon(ImageView3)
End Sub

Sub CreateComicBalloon (ImageView As B4XView)
   Dim bcGradient As BitmapCreator
   bcGradient.Initialize(ImageView.Width / xui.Scale, ImageView.Height / xui.Scale)
   bcGradient.FillGradient(Array As Int(xui.Color_White, 0xFFCACACA), bcGradient.TargetRect, "TOP_BOTTOM")
   Dim bc As BitmapCreator
   bc.Initialize(bcGradient.mWidth, bcGradient.mHeight)
   Dim brush As BCBrush = bc.CreateBrushFromBitmapCreator(bcGradient)
   Dim borderBrush As BCBrush = bc.CreateBrushFromColor(xui.Color_Black)
   Dim r As B4XRect
   r.Initialize(0, 0, bc.mWidth, bc.mHeight * 0.8)
   bc.DrawRectRounded2(r, brush, True, 0, 50)
   bc.DrawRectRounded2(r, borderBrush, False, 2, 50)
   Dim path As BCPath
   Dim len As Int = (bc.mHeight - r.Bottom) / 3
   path.Initialize(60, r.Bottom-2)
   path.LineTo(60 + len, bc.mHeight)
   path.LineTo(60 + 2 * len, r.Bottom-2)
   bc.DrawPath2(path, brush, True, 0)
   path.RemoveLastPoint
   bc.DrawPath2(path, borderBrush, False, 1)
   bc.SetBitmapToImageView(bc.Bitmap, ImageView)
End Sub
If you are creating many balloons then it is better to create the two BCs once with the maximum size and reuse them.
 

LucaMs

Expert
Licensed User
Thank you, Erel, but the question is different (my damned english :D): the label to wich I set the 9patch as background does not resize itself correctly basing on the content (its height is always wrong).

You can see this running the test project attached to the first post.
 

LucaMs

Expert
Licensed User
I have to know whether I'm badly managing the 9patches or if I draw them wrong (but also the ones I found - it's not important that they are balloons - they don't give the expected results) or what else.



[However, there is a small bug in your routine, Erel (and if anyone wanted to use it...)]


upload_2019-6-13_18-15-25.png
 

Peter Simpson

Expert
Licensed User
I have to know whether I'm badly managing the 9patches or if I draw them wrong (but also the ones I found - it's not important that they are balloons - they don't give the expected results) or what else.

[However, there is a small bug in your routine, Erel (and if anyone wanted to use it...)]
View attachment 81275
I would say your 1st speech bubble is way too small. In any case Erel's code is simple enough to adjust, you can move the bottom 'V' over yourself silly.

Oh btw creating a 9 Patch image is extremely simple, I created a post or two on here a long time ago about 9 Patch. Your best bet is to watch a couple of YouTube videos about 9 Patch and learn from them.
 

LucaMs

Expert
Licensed User
I have posted that bubble/balloon in the 2nd post just to say that I tried also that 9patch image found on Internet and this one too does not "work" as I expected, just to say that the problem does not seem how I create 9patch images. I might want to display text in a very different form than that.

Please, run the test project, if you want to understand what I mean (in it, as I said, I tried a 9patch image
tmback.9.png

found on b4x, exactly here:
https://www.b4x.com/android/forum/threads/class-custom-toast-messages.18926/
and even that class does not show texts correctly, because of the same reason: the height will be not automatically set well).


Thank you.
 

LucaMs

Expert
Licensed User
I don't know what the reason is, maybe I don't know how to use it, but the images "created" with the google tool (old tool, currently you can use it only from within Android Studio, which I really don't like) don't give the desired results, while those generated by this online tool do.
 

Peter Simpson

Expert
Licensed User
It works 100%, your doing it incorrectly. Even in my challenge 2 video on the forum I use a 9 Patch image with the photos to show the item stock images (bottom right corner line), actually most of my apps I use 9 Patch with absolutely no issues whatsoever.

I tell you what your problem is, when something is not as you expect it you ALWAYS blame the tools and never the developer (YOU), it's becoming extremely tiresome. I've watched you over the years say that things don't works as you expected when they clearly do most of the time, it's the developer, don't you get it. I clearly remembered when you ranted, raved and moaned profusely about the designer, designer script and anchors on multiple occasions claiming there were big issues and that things are not good with it, everything is incorrect and you are correct (in your mind), you just can't help yourself. Take a long look at yourself and learn a few things.

Well @LucaMs I'm telling you that YOU are doing it incorrectly.

Welcome to my ignore list, done...
 
Last edited:

LucaMs

Expert
Licensed User
It works 100%, your doing it incorrectly.
(Post #1)
Where am I wrong?
(Post #8)
maybe I don't know how to use it

Can you, Peter (*) (or DonManfred, Erel or anyone else) try this simple test project, please?

Note that:

1) when you click on "Show" the first time, the label (with 9 patch as background) will be N high (and wrong), the second time it will be N*M (and still wrong), this despite the very simple code;
2) I use StringUtils.MeasureMultilineTextHeight to resize the label and this is why I show a second blue label, to check its result (and it is correct);
3) this is how the 9 patch looks in the Google's tool:
1.gif



Is my 9png wrong? Ok, change it with your own.

Finally, I don't think the initial size of the label matters, since MeasureMultilineTextHeight will be applied to it and because the background will be set to the 9 patch image; so, please, do not change its size.


Thank you.


P.S. this is how the project looks:
1.gif



(*) P.P.S. I hadn't seen this:
Welcome to my ignore list, done...
and I don't understand why but it's ok.
 

Attachments

Last edited:

klaus

Expert
Licensed User
When done correctly it works OK.

upload_2019-6-18_13-41-36.png


The problem is the Padding!
su.MeasureMultilineTextHeight(Lbl, Text) doesn't take into account the Padding.
Therefore you must first get the padding values and then define a new label without the padding, measure the height and add the top and bottom padding values to the height.
And another point:
You adjust the height before adding the 9patch image. This means that the padding is not yet known!

Attached a modified version of your project.

The Adjustment routine:
B4X:
Sub AdjustLabelHeight(Lbl As Label, Text As String ,TextSize As Float)
    Private jolbl As JavaObject
    Private pl, pt, pr, pb As Int
 
    jolbl = Lbl
    pl = jolbl.RunMethod("getPaddingLeft", Null)
    pt = jolbl.RunMethod("getPaddingTop", Null)
    pr = jolbl.RunMethod("getPaddingRight", Null)
    pb = jolbl.RunMethod("getPaddingBottom", Null)
 
    Private lblDummy As Label
    lblDummy.Initialize("")
 
    Activity.AddView(lblDummy, 0, 0, Lbl.Width - pl - pr, Lbl.Height - pt - pb)
    lblDummy.Text = Text
    lblDummy.TextSize = TextSize
    Lbl.Text = Text
    Lbl.TextSize = TextSize
    Dim su As StringUtils
    Lbl.Height = su.MeasureMultilineTextHeight(lblDummy, Text) + pt + pb
    lblDummy.RemoveView
End Sub
EDIT: 2019.06.19
The same routine using the Padding property instead of a JavaObject.
B4X:
Sub AdjustLabelHeight(Lbl As Label, Text As String ,TextSize As Float)
    Private pd(4) As Int 
    pd = Lbl.Padding 
    Private lblDummy As Label
    lblDummy.Initialize("")
  
    Activity.AddView(lblDummy, 0, 0, Lbl.Width - pd(0) - pd(2), Lbl.Height - pd(1) - pd(3))
    lblDummy.Text = Text
    lblDummy.TextSize = TextSize
    Lbl.Text = Text
    Lbl.TextSize = TextSize
    Dim su As StringUtils
    Lbl.Height = su.MeasureMultilineTextHeight(lblDummy, Text) + pd(1) + pd(3)
    lblDummy.RemoveView
End Sub
 

Attachments

Last edited:

LucaMs

Expert
Licensed User
First of all, thank you Klaus for having tried and solved the problem (you're always willing to help, great Klaus).

The problem is the Padding!
I had thought to Padding but I knew (or thought I knew) that it was fixed for each type of View and that it didn't depend on the content.
Thinking this, I did a log of the padding of an empty label, without text, and the log showed all zeros. I had also did the same test on a Button and an EditText and these have different default values.
Imagine that it is only in this way, at @LordZenzo's suggestion, that I discovered that "now" the views have the Padding property while I had used one of your precious snippets.

However it was as I thought, the padding is fixed; it changes just with the application of the 9Patch which, as you rightly observed, must be done before changing the text, in this case before using the MeasureMultilineTextHeight.

I renew my thanks to you, Klaus, for having tried, for having solved, for explaining and also for having taken seriously my request while others ignored it and someone had only the bad idea to offend (some petty person whom sooner or later life will give him what he deserves; but it has probably already been done).
 
Last edited:

sorex

Expert
Licensed User
padding can be changed since Android 2.2 or even earlier.

the problem is with IOS where you need to do some other trickery if you want centered text look exactly the same as on Android.
(padding, kerning behaves strange there)
 

Erel

Administrator
Staff member
Licensed User
First of all, thank you Klaus for having tried and solved the problem (you're always willing to help, great Klaus).
I agree with this statement.

I renew my thanks to you, Klaus, for having tried, for having solved, for explaining and also for having taken seriously my request while others ignored it
I don't agree. Other members have tried to help you. I created a full example based on a different approach just to help you solve your problem. Even if it was not useful for you it doesn't mean that I haven't invested quite a lot of time in writing this code (post #3).

If I were to implement such solution I would have chosen the drawing approach as it is more flexible. Adding the text should be simple.
 

LucaMs

Expert
Licensed User
I renew my thanks to you, Klaus, for having tried, for having solved, for explaining and also for having taken seriously my request while others ignored it
I don't agree. Other members have tried to help you. I created a full example based on a different approach just to help you solve your problem. Even if it was not useful for you it doesn't mean that I haven't invested quite a lot of time in writing this code (post #3).

If I were to implement such solution I would have chosen the drawing approach as it is more flexible. Adding the text should be simple.
I know that you, Erel, have spent time developing that useful routine that I appreciate and also I want to study it (I want to study everything about CreateBitmap) and thank you again but what I wanted to understand was if I had a wrong idea about how 9patches work or if I used them badly. The only member who downloaded one of the two projects I attached was Klaus.

Someone may have thought that I was criticizing the 9patches (re-reading Klaus's post, perhaps even himself, given the first line he wrote).
 

LucaMs

Expert
Licensed User
A slightly modified version.
B4X:
' Returns the number of text lines.
Sub AdjustLabelHeight(Lbl As Label) As Int
    Dim lblDummy As Label
    lblDummy.Initialize("")
    Dim Parent As Panel = Lbl.Parent
    Parent.AddView(lblDummy, 0, 0, Lbl.Width - Lbl.Padding(0) - Lbl.Padding(2), Lbl.Height - Lbl.Padding(1) - Lbl.Padding(3))
    lblDummy.Text = Lbl.Text
    lblDummy.TextSize = Lbl.TextSize
    lblDummy.Typeface = Lbl.Typeface
    Dim su As StringUtils
    Lbl.Height = su.MeasureMultilineTextHeight(lblDummy, Lbl.Text) + Lbl.Padding(1) + Lbl.Padding(3)
    lblDummy.RemoveView

    Dim Source As JavaObject = Lbl
    Dim LineCount As Int = Source.RunMethod("getLineCount", Null) + 1
    Return LineCount
End Sub
 
Top