4

I have a requirement where the letters in a TextView need to be spaced a little farther apart. Unfortunately, most of the resources I find seem to say this cannot be done--at least not easily.

So far, the apparent solutions are:

  1. Add spaces in between the characters in the String-- "A B C" instead of "ABC". Of course, that doesn't work if only a LITTLE more space is needed.
  2. Change textScale, but that affects the size of the letters, not just the spacing between letters
  3. Use the Font class, but that isn't available until Honeycomb (I need something Gingerbread compatible) and it has been deprecated in JellyBean, so that's not a good option.
  4. Find a font with different kerning, but that's not practiif clients want to use the same font.
  5. Override onDraw for a View, drawing characters to the Canvas one character at a time, manually specifying exactly where each character should be drawn.

Is there something I'm missing? It seems like there should be a better way. I see TextAttribute.KERNING and TextAttribute.TRACKING... it seems like those should be able to be used easily, but I can't figure out how.

What's the best way to change the spacing between letters in a TextView?

Anas Azeem
  • 2,820
  • 3
  • 24
  • 37
Chad Schultz
  • 7,770
  • 6
  • 57
  • 96
  • "most of the resources I find seem to say this cannot be done--at least not easily" -- AFAIK, those resources are correct. "4. Find a font with different kerning, but that's not practical if clients want to use the same font." -- assuming that you have licensed the font and are allowed to make modifications, load it up in a font editor and adjust the kerning to suit. – CommonsWare Jan 11 '13 at 17:18

3 Answers3

4

The solution I found is to mix the solutions 1 and 2 that you described. Adding spaces between letters and than changing the TextScaleX only of the spaces, so you keep other characters the same. I built a custom class that extends TextView and allows you to define the letter spacing. Everything else is automatic =)

I posted the class on this other answer

Hope that helps ^^

Community
  • 1
  • 1
Pedro Barros
  • 1,326
  • 1
  • 12
  • 19
  • Complex, but it may be the only solution--thanks! I haven't tried it yet, but I'll keep it in mind next time I have that requirement. – Chad Schultz May 09 '13 at 14:21
3

This answer is based on Pedro's answer but editted so it also works when text attribute is allready set:

package nl.raakict.android.spc.widget;
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ScaleXSpan;
import android.util.AttributeSet;
import android.widget.TextView;


public class LetterSpacingTextView extends TextView {
    private float letterSpacing = LetterSpacing.BIGGEST;
    private CharSequence originalText = "";


    public LetterSpacingTextView(Context context) {
        super(context);
    }

    public LetterSpacingTextView(Context context, AttributeSet attrs){
        super(context, attrs);
        originalText = super.getText();
        applyLetterSpacing();
        this.invalidate();
    }

    public LetterSpacingTextView(Context context, AttributeSet attrs, int defStyle){
        super(context, attrs, defStyle);
    }

    public float getLetterSpacing() {
        return letterSpacing;
    }

    public void setLetterSpacing(float letterSpacing) {
        this.letterSpacing = letterSpacing;
        applyLetterSpacing();
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        originalText = text;
        applyLetterSpacing();
    }

    @Override
    public CharSequence getText() {
        return originalText;
    }

    private void applyLetterSpacing() {
        StringBuilder builder = new StringBuilder();
        for(int i = 0; i < originalText.length(); i++) {
            String c = ""+ originalText.charAt(i);
            builder.append(c.toLowerCase());
            if(i+1 < originalText.length()) {
                builder.append("\u00A0");
            }
        }
        SpannableString finalText = new SpannableString(builder.toString());
        if(builder.toString().length() > 1) {
            for(int i = 1; i < builder.toString().length(); i+=2) {
                finalText.setSpan(new ScaleXSpan((letterSpacing+1)/10), i, i+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
        super.setText(finalText, BufferType.SPANNABLE);
    }

    public class LetterSpacing {
        public final static float NORMAL = 0;
        public final static float NORMALBIG = (float)0.025;
        public final static float BIG = (float)0.05;
        public final static float BIGGEST = (float)0.2;
    }
}
Bart Burg
  • 4,786
  • 7
  • 52
  • 87
2

As of API 21, you can use setLetterSpacing() fot TextView (and Paint) objects.