Tuesday, May 6, 2014

Not editable prefix in EditText

Today I have decided to start sharing my "simple and brilliant" ideas with the world. I don't know if I will continue to do such things in the future but, at least, it worth to try.

So what to start with...

Probably with the latest task I have tried to solve on Android. The task was simple enough - show not editable phone prefix in EditText. Something like this:



Most of the time I try to optimize my code so it implies some limitations:

  1. it must work fast. Actually, it will be a bigger challange for me to make such a simple control work slowly :)
  2. minimize view hierarchy - no need to use "Linear -> Text -> Edit" here
  3. code must look good without any dirty hacks
  4. generalization is good most of the times but no need to be a fanatic
So lets start. Idea is to extend EditText and to override four methods:
  1. onMeasure - to calculate prefix size
  2. onLayout - to position prefix correctly
  3. onDraw - to actually draw prefix
  4. getCompoundPaddingLeft - to offset EditText's content
Here is full class code:

public class PhoneNumberEdit extends EditText {

  private String mPrefix = "+3"; // can be hardcoded for demo purposes
  private Rect mPrefixRect = new Rect(); // actual prefix size

  public PhoneNumberEdit(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    getPaint().getTextBounds(mPrefix, 0, mPrefix.length(), mPrefixRect);
    mPrefixRect.right += getPaint().measureText(" "); // add some offset

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawText(mPrefix, super.getCompoundPaddingLeft(), getBaseline(), getPaint());
  }

  @Override
  public int getCompoundPaddingLeft() {
    return super.getCompoundPaddingLeft() + mPrefixRect.width();
  }
}