Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Spannable Line Height

I have been trying to figure this one out for the last couple of days now, and have had no success...

I'm learning android right now, and am currently creating a calculator with history as my learning project. I have a TextView that is responsible for displaying all history... I'm using a digital font that looks like a calculator font, but this only looks good for digits and decimals and comma's. I want all operators to be highlighted and in a different font (Arial Narrow at the moment). I have been able to get this to work beautifully using a spannable string where I'm specifying a font color as well as a font using a CustomTypeFaceSpan class to apply my custom fonts.

The problem... When I mix the Typefaces, there seems to be an issue with the line height, so I found this post which demonstrates using another custom defined class to apply a line height to each added line of spannable text:

public class CustomLineHeightSpan implements LineHeightSpan{
    private final int height;

    public CustomLineHeightSpan(int height){
        this.height = height;
    }

    @Override
    public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, FontMetricsInt fm) {
        fm.bottom += height;
        fm.descent += height;
    }

}

This does not seem to work, and I can not figure out why. If I don't apply the different typefaces, then it displays as expected with no space above the first line, and about 5px spacing between lines. When I apply the alternate typefaces, there is a space of about 10 to 15px above the first line of text and the line spacing is about the same 10 to 15px.

There is no difference in the font size, only the typeface. What am I missing. I implemented the CustomLineHeightSpan which implements LineHeightSpan and overrides the chooseHeight method. I call it like so:

WordtoSpan.setSpan(new CustomLineHeightSpan(10), operatorPositions.get(ii), operatorPositions.get(ii) + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

It does not seem to matter what I put in the call to CustomLineHeightSpan. Nothing changes...

Anybody have any idea what I'm missing... I'm sure it's an "I can't believe I missed that" answer, but can't seem to figure it out at the moment.

Thanks for the help guys :-)

like image 326
titanic_fanatic Avatar asked Oct 16 '12 15:10

titanic_fanatic


People also ask

How do I change line spacing in Android?

Double-tap the place in your document you want to edit. tap Paragraph. Next to "Line spacing," use the arrows to choose the amount of space you want between the lines in the paragraph.

What is Spannable in Android?

Spannable is a Spanned , adding in the ability to modify the spans (to add or remove formatting), but not to modify the text itself. SpannedString is a concrete implementation of the Spanned interface. SpannableString is a concrete implementation of the Spannable interface.

What is TextAppearance in Android?

TextAppearance allows you to define text-specific styling while leaving a View 's style available for other uses. Note, however, that if you define any text attributes directly on the View or in a style, those values would override the TextAppearance values.


1 Answers

I finally found a more in depth example of the use of LineHeightSpan... Actually LineHeightSpan.WithDensity to be more precise... The following is the excerpt that helped me to resolve my issue:

private static class Height implements LineHeightSpan.WithDensity {
    private int mSize;
    private static float sProportion = 0;

    public Height(int size) {
        mSize = size;
    }

    public void chooseHeight(CharSequence text, int start, int end,
                             int spanstartv, int v,
                             Paint.FontMetricsInt fm) {
        // Should not get called, at least not by StaticLayout.
        chooseHeight(text, start, end, spanstartv, v, fm, null);
    }

    public void chooseHeight(CharSequence text, int start, int end,
                             int spanstartv, int v,
                             Paint.FontMetricsInt fm, TextPaint paint) {
        int size = mSize;
        if (paint != null) {
            size *= paint.density;
        }

        if (fm.bottom - fm.top < size) {
            fm.top = fm.bottom - size;
            fm.ascent = fm.ascent - size;
        } else {
            if (sProportion == 0) {
                /*
                 * Calculate what fraction of the nominal ascent
                 * the height of a capital letter actually is,
                 * so that we won't reduce the ascent to less than
                 * that unless we absolutely have to.
                 */

                Paint p = new Paint();
                p.setTextSize(100);
                Rect r = new Rect();
                p.getTextBounds("ABCDEFG", 0, 7, r);

                sProportion = (r.top) / p.ascent();
            }

            int need = (int) Math.ceil(-fm.top * sProportion);

            if (size - fm.descent >= need) {
                /*
                 * It is safe to shrink the ascent this much.
                 */

                fm.top = fm.bottom - size;
                fm.ascent = fm.descent - size;
            } else if (size >= need) {
                /*
                 * We can't show all the descent, but we can at least
                 * show all the ascent.
                 */

                fm.top = fm.ascent = -need;
                fm.bottom = fm.descent = fm.top + size;
            } else {
                /*
                 * Show as much of the ascent as we can, and no descent.
                 */

                fm.top = fm.ascent = -size;
                fm.bottom = fm.descent = 0;
            }
        }
    }
}

This was taken from this example.

What it does is as quoted below:

Forces the text line to be the specified height, shrinking/stretching the ascent if possible, or the descent if shrinking the ascent further will make the text unreadable.

I hope this helps the next person :-)

like image 180
titanic_fanatic Avatar answered Oct 09 '22 20:10

titanic_fanatic