Spinner Text Height

Roger Garstang

Well-Known Member
Licensed User
Longtime User
How do I get the text height of a spinner control? String Utils function doesn't work and gives a Java error that it is expecting an Edit Text and I gave it a spinner...I can't fool it by dimming an EditText and pointing it to the spinner either...I tried, and I don't want to create an EditText and add it to the panel just to get the text size.

I had another thread where I had text size issues lately too where the Canvas version and the String Util version aren't working the same for some reason. Canvas text width seems to work fine, but height does not give the same results. Even when I use reflection to set the padding to 0 the width from canvas is always too small. I tried with a couple font sizes like 18 and 38, with 18 it was 9 pixels too small and with 38 it was 18 pixels too small. The amount they are too small seems to be pretty close to 50% of the full size. It is like the Canvas version isn't considering full line spacing or something.

Even the String Utils version isn't perfect though and sometimes would be off by just a bit. To actually get the correct result in an Edit Text I have to setpadding to 0 on all 4 sides, set the width to match the needed text width (Otherwise it tries to wrap the given text within the current width and gives that height), then I get the height and add some dips to it and the width that match my 9 Patch then set the 9 Patch which automatically sets the padding and everything is good.

Any chance on seeing the actual functions/code that is called for the Canvas Height and String Utils Height to see what the difference is and how to get this to work right?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can use a hidden label or EditText to measure the text height with StringUtils. I think that this is your best option.

I recommend using StringUtils to calculate the required height.
I don't think that the Java code will be too meaningful. Here it is:
B4X:
   public float MeasureStringHeight(String Text, Typeface Typeface, float TextSize) {
      paint.setTextSize(TextSize * BA.applicationContext.getResources().getDisplayMetrics().scaledDensity);
      paint.setTypeface(Typeface);
      paint.setStrokeWidth(0);
      paint.setStyle(Style.STROKE);
      paint.setTextAlign(Align.LEFT);
      Rect r = new Rect();
      paint.getTextBounds(Text, 0, Text.length(), r);
      return r.height();
   }


   public int MeasureMultilineTextHeight(TextView TextView, String Text) {
      StaticLayout sl = new StaticLayout(Text, TextView.getPaint(), 
            TextView.getLayoutParams().width - TextView.getPaddingLeft() - TextView.getPaddingRight(),
            Alignment.ALIGN_NORMAL, 1, 0 , true);
      return sl.getLineTop(sl.getLineCount());
   }
 
Upvote 0

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Interesting. So, the function already strips out the padding. Wonder why I have to strip it out too to get accurate results? Looks like whatever is returned doesn't do anything with Height Padding, although I'd think it would return bigger then and not smaller (Usually comes back like 1-5 pixels too small in height if I don't strip the padding out first). The Line Top stuff is confusing too, so it measures from bottom up?

What is the difference between Paint and TextPaint? Couldn't that be created like it is in MeasureStringHeight instead of having to get it from the View? Or wouldn't all views have a getPaint? Why does it have to be a TextView? Seems like that could have been any View. All views may not have padding, but so far it seems all the ones with text do...if I'm wrong, that could be tested for and adjusted if the View has padding.

How would recreating this in something like Reflection Code look, or would it need to be in a Library or Core Code? I already use getPadding and setPadding stuff. I'd just need a way to create the needed Paint/StaticLayout and call the function.
 
Upvote 0

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Just got in to work and tested it without my:

B4X:
ref.RunMethod4("setPadding", Array As Object(0, 0, 0, 0), Array As String("java.lang.int", "java.lang.int", "java.lang.int", "java.lang.int"))

I had it backwards...must have been thinking of the canvas version. If left out it actually makes it include the height padding and makes it too big. I guess it depends on how this needs to be used. What is difficult is really this needs used before the View is added to the Activity/Panel otherwise the Background (Android's or my 9 Patch) draws wrong [It is like it uses whatever piece of the background fits within the current width/height and stretches it]. I end up adding it with a size of 1 then making the width what I need to call this and finally setting my 9 Patch to it to draw right. So, all I need is the text measurements without padding for any type of control/view.

Having a Width method in String Utils would be awesome too so I can use one class.
 
Last edited:
Upvote 0

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Been looking at this a little more and trying to come at it with a different angle. In looking up info on it I came across em units...much like the em units in HTML that I love using. They appear to be able to give some of the ability I need by specifying width in font width (Max Char width of the font...that used to be derived from the letter M hence the em). In my class I had figured an average char width using the entire upper and lower case alphabet, but the average made it way off (Way too wide or too small depending on input). It would be really cool to be able to specify like this, but the SetMinEms and SetMaxEms methods report not found for an Edit Text and setEms doesn't appear to do anything.

There are a few more somewhat useful functions:

For the default 18 TextSize-
getTextSize returns 27
The String Util height measurement of letter M (Assuming it is max) reports 37.
getLineHeight reports 31 (Really close and there is a getLineSpacingExtra that sounded like it would get the extra space, but gives an error that it doesn't exist)

getPaint looks like it returns the TextPaint that is used in your Java code, and says it extends Paint. Paint has some values including Font Metric type stuff that look like they would be more useful than the line measuring functions.

Is it possible to somehow set width in em or get the em value and/or have some functions in StringUtil that would get the Max Char width and height of a font (Not measuring a line, just getting the max size a char can be for that font)? This would be the best way to go about this and size it the size needed.
 
Last edited:
Upvote 0

Roger Garstang

Well-Known Member
Licensed User
Longtime User
The String Utils method works ok, but I end up having to deal with padding. With each type of view I have to do different things with padding to get the correct result since it removes width padding but does nothing with height, plus some views have no padding. Just before leaving work the other day I found ICS is a little picky on the width too. I turn on the animated / marquee effect on my labels so if the width is too small they will slide into view. When I set the label to the exact width and height needed for the text it shows fine on Gingerbread, but animates on ICS like it is a couple pixels too small or something. I also would like to be able to measure the text without creating another view since Spinner isn't allowed in the measure sub in String Util. (Whatever control I use to measure would have different padding and such too, so could return the wrong results anyway)

I think what I need is something to get font info...if possible without even needing to add a view yet. Just pass it the typeface info and font size and it returns the maximum height in pixels needed to show any char of that font and the max char width.

To do this currently I'd have to:
1. Create a string of every printable char.
2. Create a Label or Create a Text View and Remove Padding.
3. Set the view width to the width of the string using Canvas Class.
4. Pass all this to the StringUtil function to get the height and hope the Canvas width function gave enough room and/or there were no padding issues otherwise the StringUtil function will return a double height do to wrapping (I have found usually removing padding helps this, so StringUtil sub is more accurate). [At this point we have Max height after 4 steps]
5. Then using a For loop or something we pass each char to the Canvas width sub to figure max char width. [Now I have width needed].

If able to specify width in em it would remove the need for the overhead of step 5 (Being able to get Min/Max em to work for auto expanding controls would be cool too). If able to get font info I could have all info needed in one step...possibly even without needing to create a view, so would allow me to create any view to the proper size and draw correctly.

Some type of a sub like:

GetCharFrame(FontTypeface as Typeface, FontSize as Float) as Rect

or if we have a FontMetrics type it could return it and calculations could be made from that info (Some info like line spacing may be needed too if not included in the GetCharFrame calculation). It should give ascender and descender info...one of which is negative. I also saw a Top/Bottom in there too that might return the correct result. Width I think is given in a scale of height, so would need calculated.
 
Last edited:
Upvote 0
Top