Adding a prefix to an EditText

Adding an always visible prefix to an EditText is surprisingly hard! Users can delete your prefix, type or paste text in the middle of it. Handling this in a TextWatcher is a lot of code. However, there is an easier way!

Using a TextWatcher to add an always visible prefix is fairly complicated, if someone clicks in the middle of your prefix, you have to intercept the text and move it to the end or more the cursor to the end immediately. All of this can result in a LOT of code. You need to disable copy/paste, you need to handle onClick, you need to handle text change etc.

An other approach may be to put a TextView in the background and add padding to the EditText, however, it’s tricky to align the background text and the EditText. The reason for that is that padding is in DIPs and text sizes are in SP. If you do get things to align perfectly, fragmentation of the EditText view, accessibility changes and different devices densities may still cause the text to show up unaligned. Look at compatibility issues here for more on EditText fragmentation.

The best way I can think of to address this issue is to create a custom EditText which literally uses the same paint object to draw the prefix text and and add padding according to the prefix text size. Below is some quick and dirty code to do the same. The below example prefixed the EditText with a country code for input of phone numbers (for example).

Notes:

  • It doesn't support prefix text changing at the moment, but I think looking at the code, it’s pretty obvious how you can support it.
  • I also use tag to pass in the prefix. This could be a bad idea, so you may be better off adding a custom attribute.
  • Also, I haven’t bothered to check to right to left displays but that should be simple enough.
  • Finally, TalkBack won’t be able to read the prefix.

The result

The code

public class PrefixEditText extends AppCompatEditText {
float mOriginalLeftPadding = -1;

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

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

public PrefixEditText(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
calculatePrefix();
}

private void calculatePrefix() {
if (mOriginalLeftPadding == -1) {
String prefix = (String) getTag();
float[] widths = new float[prefix.length()];
getPaint().getTextWidths(prefix, widths);
float textWidth = 0;
for (float w : widths) {
textWidth += w;
}
mOriginalLeftPadding = getCompoundPaddingLeft();
setPadding((int) (textWidth + mOriginalLeftPadding),
getPaddingRight(), getPaddingTop(),
getPaddingBottom());
}
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String prefix = (String) getTag();
canvas.drawText(prefix, mOriginalLeftPadding,
getLineBounds(0, null), getPaint());
}
}

Usage:

<com.alimuzaffar.customwidgets.PrefixEditText
fontPath="fonts/Lato-Light.ttf"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:textSize="24sp"
android:tag="+61 "
android:text="1234" />

Another approach

Another approach and in some respects a better approach may be to create a custom drawable and add it as a drawable right or drawable left. The custom drawable will simply draw the text. The reason I didn’t choose this approach is:

  • I would have to pass in the paint object or build one from the theme, why bother when EditText already contains one.
  • Aligning the text drawn by my drawable with the EditText is not going to be easy and prone to getting misaligned.
  • To fix both the issues above, the best approach would be to pass a reference to the EditText to our Drawable, and this code is just becoming messy at that point IMHO.

UPDATE 7th March 2016: I created a TextDrawable that you can use to add a prefix to an EditText or use emojis, Unicode characters or text as a Drawable.

Finally

In order to build great Android apps, read more of my articles.


Yay! you made it to the end! We should hang out! feel free to follow me on Medium, LinkedIn, Google+ or Twitter.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.