There is a methods that multiply spacing between lines in TextView
lineSpacingMultiplier
I want to multiply it by 2 , but what is the default spacing value that it multiplies? 2px, 5px?
Thanks.
The value is a 17.1 percent of the text size.
But use 20 percent to be sure that letter like j or g appear correctly
After some messing around with Spans, I finally found how to find the default line spacing (the space from the lowest glyph (y) in a line to the tallest glyph (L) in the next line). Here is the code:
public static int getLineSpacing(TextView textContainer){
Paint.FontMetricsInt fontMetrics = textContainer.getPaint().getFontMetricsInt();
return fontMetrics.ascent - fontMetrics.top;
}
Related
I have a TextView with lines = 2. I get a different result in the height of the TextView if I set a short text and only 1 line shows up, or I set a longer text and 2 lines show up. This seems to be an issue with the onMeasure function of TextView. In the code I can see that first the height of the Layout is calculated, and then a line height is added for each blank line. Javadoc notes the following:
Note that markup within the text can cause individual lines to be taller or shorter than this height, and the layout may contain additional first-or last-line padding.
These TextViews are used in a horizontal RecyclerView where I need each list item to be the same height, that's why I set the lines fixed to 2. But apparently that doesn't make it the same height. How can this be fixed?
Some extra info regarding the TextView:
Font: Helvetica Neue Lt Std Bold
Text size: 18 sp
Lineheight: 32 sp
Either it has something to do with the lineheight not being used in the calculation of getLineHeight or Layout. Or something with the font itself. Edit: it's definitely something with the font because lineheight + roboto doesn't create this issue.
Here you can see the difference in height:
And here the TextViews have the same height because they all have the same number of lines.
I want to calculate the ems value according to the string or text length count If text length increase it should occupy it's width size according to the characters count without cut-off text in a single line, thanks
Tried to keep string length as ems but it gives very long width size with empty spaces, Thanks in advance
Using monospaced fonts you could count the em-width of a string. Since letters like i and m do in other cases not have the same length, the pixel/em/dp count cannot be predicted.
If someone would write a sophisticated logic for the widths of letters, count them, then multiply count with per-letter-length, this solution would still be too inaccurate without even more refinements: Ligatures and kerning make the actual width of a word even more complex. For example, A and V can overlap a little, while a capital A following another A or the letter V following another V are same width at at base or top, respectively. Therefore their centers have to be moved away from each other so as to not overlap.
I'm trying to draw text using Canvas and have found that using StaticLayout would take care of the line breaks automatically. I also want to limit its height so that when text is too long it would be ellipsized, but the size of text container is dynamic. I can easily apply the width to StaticLayout, but cant find a way to do height.
I tried to utilize TextUtils.ellipsize(), but having issue to get the spacing between lines.
PerracoLabs has the right answer but, as CheokYanCheng stated, the calculation of the maximum number of lines is off (although it may yield the correct result many if not most of the time).
A maximum height cannot be specified for a StaticLayout except indirectly by specifying the maximum number of lines. Ellipsis is tied to the maximum line count anyway, so determining the maximum number of lines for a specific height to back into a solution is the way to go. So, how do we determine the appropriate maximum line count so that a fixed-size StaticLayout with ellipsis can be created as PerracoLabs has explained.?
If the text has no spans that effect the height any of the lines of text then a simply calculation can determine the maximum number of lines that will fit into a StaticLayout before ellipsis.
The following Kotlin function will determine how many lines of text will fit into a view that has a fixed height and width. It is assumed that each line of a StaticLayout has a set height (no height-effecting spans). The top line has the same height of other lines but it is augmented by a top padding. The bottom line has a bottom padding added to it.
private fun getMaxLines(maxHeight: Int): Int {
// Build a dummy StaticLayout to get the internal measurements.
return makeStaticLayout("", width, 1).run {
val lineHeight = getLineBottom(0) - getLineTop(0) + topPadding - bottomPadding
(maxHeight - topPadding - bottomPadding) / lineHeight
}
However, if the text contains a span that changes the height of one or more lines then the only way to calculate the maximum number of lines is through the creation of the static layout that holds the entire text (no ellipsis) followed by an inspection of the lines within the layout to determine how many complete lines have fit. A new StaticLayout can then be created with the calculated maximum lines determined from the inspection.
The following Kotlin function will calculate the maximum lines by inspecting the StaticLayout for the last full line that is present.
private fun getMaxLinesByInspection(staticLayout: StaticLayout, maxHeight: Int): Int {
var line = staticLayout.lineCount - 1
while (line >= 0 && staticLayout.getLineBottom(line) >= maxHeight) {
line--
}
return line + 1
}
I have posted a small project on GitHub as a demonstration.
Here is a screen shot of the app.
You (and #Cheok Yan Cheng) might try to make use of PagedTextView. The view is intended for Paginating text in Android.
The view partially solves the problem, i.e. reacts to dynamic size changes. As to text ellipsizing, you might achieve this by customising the algorithm I've used for measuring text in height.
I would like to be able to set the text in a TextView depending on the available space, in order to avoid ellipsizing.
For example:
if there is enough space set the text "The red fox jumps"
if there is not enough space (and consequently "The red fox jumps" would be ellipsized) set the text "jumps"
Please how can I achive that?
You could use Paint.measureText(String) to determine the width of the whole string, when drawn with your Paint object. If that value is greater than the TextView's width, then we know that the text will be ellipsised.
float totalLength = myPaint.measureText("The red fox jumps");
float tvWidth = myTextView.getWidth(); // get current width of TextView
if (tvWidth < totalLength) {
// TextView will display text with an ellipsis
}
Once we know the text will be truncated, we can use trial and error to determine what the minimum text that can be displayed on screen is. This step will depend on your business logic, but should use the same Paint calculations as the first step.
calculateStringWidth("The red fox jumps"); // too large
calculateStringWidth("red fox jumps"); // still too large
calculateStringWidth("fox jumps"); // width is less than TextView, will fit without ellipsis
One method would be to calculate the neede size for given text.
textView.setText("The red fox jumps");
// call measure is important here
textView.measure(0, 0);
int height = textView.getMeasuredHeight();
int width = textView.getMeasuredWidth();
if (height > availableHeight || width > availableWidth) {
textView.setText("jumps");
}
The call of measure() "determines the size requirements for this view and all of its children". Referring to Androids View doc. Documentation
I'm adding line spacing in my textview which spans multiple lines.
What's the difference between android:lineSpacingExtra and android:lineSpacingMultiplier?
lineSpacingExtra with 2dp worked fine for me but I was wondering what the Multiplier does instead?
The difference is that android:lineSpacingExtra add extra spacing between lines of text of TextView and android:lineSpacingMultiplier work as scale factor for height of line space. in other words, each line height will be height*multiplier + extra
It's rather simple: one is additive and one is multiplicative.
If you have a default line spacing of LINE_SPACING and use:
float x = 2;
float y = 1.5;
setLineSpacing(x, y);
The resulting line spacing will be 1.5*LINE_SPACING + 2
It is important to note that the multiplication happens first! This follows the conventional order of operations (multiplication before addition).
See the docs here: http://developer.android.com/reference/android/widget/TextView.html#setLineSpacing(float, float)
In the future, it might be wise to look up such documentation first. ;)