Search code examples
androidstringpaintmeasure

Paint.measureText: Is the sum of the parts equal to the whole?


If I have a string like this

String myString = "This is some text.";

Will I get the same lengths if I measure the entire string as when I take the sum of measuring each character?

At first thought, I assumed the answer to be yes, but then I was reading this answer, which said measureText adds an AdvanceX value before and after each measurement. If that is true, then it would add a subtle error into measuring summed lengths (because there would be double padding between each character).

I also know that there is kerning with some fonts that changes how close letters are placed together depending on the surrounding text. This is making me think more and more that a sum of the parts will be different than the whole.

kerning

The image comes from Wikipedia.

This is important because I am making my own custom text view that needs to handle line wrapping. If a single word is too long for the line then I measure each character until I discover where I need to break. However, I assumed that summing the measure of the individual character widths would be the same as measuring the whole string.

I have set up this question so that I can answer it below after I am finished with my tests.


Solution

  • The whole is not always equal to the sum of the parts.

    This appears to be a result of kerning and not related to any AdvanceX double padding that you mentioned.

    Test code

    Here is the test code:

    String myString = "This is some text.";
    
    Paint myPaint = new Paint();
    myPaint.setAntiAlias(true);
    myPaint.setTextSize(100);
    
    float theWhole = myPaint.measureText(myString);
    
    float sumOfTheParts = 0;
    for (int i = 0; i < myString.length(); i++) {
        sumOfTheParts += myPaint.measureText(myString, i, i + 1);
    }
    

    Results

    In my first test, the measures are the same:

    String myString = "This is some text.";
    
    theWhole        // 787.0
    sumOfTheParts   // 787.0
    

    However, when there are letters that need kerning, the measures are different. This is the test again with a different string:

    String myString = "AV Wa";
    
    theWhole        // 291.0
    sumOfTheParts   // 297.0
    

    Implications

    You cannot assume that measuring all the characters of a string and then summing the total will give you the actual length of the string. Thus, when doing text wrapping you will need to measure entire string ranges.