Put constant text inside EditText which should be non-editable - Android

80,292

Solution 1

Did u try this method?

final EditText edt = (EditText) findViewById(R.id.editText1);

edt.setText("http://");
Selection.setSelection(edt.getText(), edt.getText().length());


edt.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // TODO Auto-generated method stub

        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            if(!s.toString().startsWith("http://")){
                edt.setText("http://");
                Selection.setSelection(edt.getText(), edt.getText().length());

            }

        }
    });

Solution 2

As of version 1.2.0-alpha01 of material design library, prefix and suffix is supported for text fields:

<com.google.android.material.textfield.TextInputLayout
        app:prefixText="Price: "
        app:prefixTextAppearance="..."
        app:prefixTextColor="..."
        app:suffixText="Dollar"
        app:suffixTextColor="..."
        app:suffixTextAppearance="...">

    <com.google.android.material.textfield.TextInputEditText .../>

</com.google.android.material.textfield.TextInputLayout>

The only downside in my opinion is that the suffix is fixed at the end of the text field and there is no option to make it flow with the input text. You can vote on this issue for that.

Solution 3

That's how you can actually do it with an InputFilter:

final String prefix = "http://"
editText.setText(prefix);

editText.setFilters(new InputFilter[] {
    new InputFilter() {
      @Override
      public CharSequence filter(final CharSequence source, final int start,
          final int end, final Spanned dest, final int dstart, final int dend) {
        final int newStart = Math.max(prefix.length(), dstart);
        final int newEnd = Math.max(prefix.length(), dend);
        if (newStart != dstart || newEnd != dend) {
          final SpannableStringBuilder builder = new SpannableStringBuilder(dest);
          builder.replace(newStart, newEnd, source);
          if (source instanceof Spanned) {
            TextUtils.copySpansFrom(
                (Spanned) source, 0, source.length(), null, builder, newStart);
          }
          Selection.setSelection(builder, newStart + source.length());
          return builder;
        } else {
          return null;
        }
      }
    }
});

If you also want the prefix to be not selectable you can add the following code.

final SpanWatcher watcher = new SpanWatcher() {
  @Override
  public void onSpanAdded(final Spannable text, final Object what,
      final int start, final int end) {
    // Nothing here.
  }

  @Override
  public void onSpanRemoved(final Spannable text, final Object what, 
      final int start, final int end) {
    // Nothing here.
  }

  @Override
  public void onSpanChanged(final Spannable text, final Object what, 
      final int ostart, final int oend, final int nstart, final int nend) {
    if (what == Selection.SELECTION_START) {
      if (nstart < prefix.length()) {
        final int end = Math.max(prefix.length(), Selection.getSelectionEnd(text));
        Selection.setSelection(text, prefix.length(), end);
      }
    } else if (what == Selection.SELECTION_END) {
      final int start = Math.max(prefix.length(), Selection.getSelectionEnd(text));
      final int end = Math.max(start, nstart);
      if (end != nstart) {
        Selection.setSelection(text, start, end);
      }
    }
  }
};

editText.getText().setSpan(watcher, 0, 0, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

Solution 4

There was a slight problem with @Rajitha Siriwardena's answer. It assumes that the entire string except the suffix has been deleted before the suffix is meaning if you have the string

http://stackoverflow.com/

and try to delete any part of http:// you will delete stackoverflow.com/ resulting in only http://.

I also added a check incase the user tries to input before the prefix.

 @Override
 public void afterTextChanged(Editable s) {
     String prefix = "http://";
     if (!s.toString().startsWith(prefix)) {
         String cleanString;
         String deletedPrefix = prefix.substring(0, prefix.length() - 1);
         if (s.toString().startsWith(deletedPrefix)) {
             cleanString = s.toString().replaceAll(deletedPrefix, "");
         } else {
             cleanString = s.toString().replaceAll(prefix, "");
         }
         editText.setText(prefix + cleanString);
         editText.setSelection(prefix.length());
    }
}

Note: this doesn't handle the case where the user tries to edit the prefix itself only before and after.

Solution 5

Taken from Ali Muzaffar's blog, see the original post for more details.

Use custom EditText View to draw the prefix text and add padding according to the prefix text size:

public class PrefixEditText extends EditText {

private String mPrefix = "$"; // add your prefix here for example $
private Rect mPrefixRect = new Rect(); // actual prefix size

public PrefixEditText(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();
}
}
Share:
80,292

Related videos on Youtube

Shrikant Ballal
Author by

Shrikant Ballal

Hello, I am Shrikant Ballal, Staff Engineer - Android at YML. Interested in Android, Kotlin, Dev Tools, Processes and CI/CD.

Updated on July 08, 2022

Comments

  • Shrikant Ballal
    Shrikant Ballal almost 2 years

    I want to have constant text inside editText like:

    http://<here_user_can_write>
    

    User should not be able to delete any chars from "http://", I searched about this and found this:

    editText.setFilters(new InputFilter[] {
        new InputFilter() {
            public CharSequence filter(CharSequence src, int start,
                int end, Spanned dst, int dstart, int dend) {
                return src.length() < 1 ? dst.subSequence(dstart, dend) : "";
            }
        }
    }); 
    

    but I don't know whether it restricts user to not delete any chars from start to end limit. I also could not understand use of Spanned class.

    One way would be a good choice if we can put a TextView inside EditText but I don't think it is possible in Android since both are Views, is it possible?

  • Ε Г И І И О
    Ε Г И І И О almost 11 years
    It's safer to use startsWith rather than contains, to avoid user moving the cursor position and type anything before the constant.
  • user1767260
    user1767260 over 10 years
    but when deletes it without moving the hand from delete button the text is removed.how can I solve?
  • Aman Verma
    Aman Verma about 8 years
    i cant set the hint now..help me
  • demaksee
    demaksee over 7 years
    Also you can extend EditText and override protected void onSelectionChanged(int selStart, int selEnd) method, and in this way prevent even selecting constant text
  • Rishikesh pathak
    Rishikesh pathak about 7 years
    I have quite similar requirement but i want text "KG" in back always.when user type text.How to achieve this.please help.
  • Johnny Five
    Johnny Five about 6 years
    Make sure you use right class path in your xml file. com.alimuzaffar.customwidgets.PrefixEditText - if you use this, your app will crush.
  • Abdul Rizwan
    Abdul Rizwan almost 6 years
    this is not working in Nougat and in other OS it's working fine, can you please let me know , how can we resolve this in Nougat?
  • Marcel Bro
    Marcel Bro over 5 years
    Hey Vishal, next time you copy a code from somebody's blog (or anywhere from the internet), please remember to link to the source.
  • Vishal Jadav
    Vishal Jadav over 5 years
    Okay will do 👍
  • A moskal escaping from Russia
    A moskal escaping from Russia over 4 years
    The answer written right before yours points to the same Medium post.
  • Jakub S.
    Jakub S. over 4 years
    @SebastianPalma at the time i wrote my answer there was no link to the blog. The answer was edited.
  • Ali Obeid
    Ali Obeid almost 4 years
    The EditText field stopped receiving any input. can't type anything in it. I believe this solution is not working anymore.
  • Sadda Hussain
    Sadda Hussain over 3 years
    How would you set text on this edittext? .setText() does not seem to be working.
  • PriyankVadariya
    PriyankVadariya over 2 years
    Any way to update PreFix? I want to change after user perform some task
  • Antonis Radz
    Antonis Radz over 2 years
    I think you can try remove old one and new one, just make some adjustments to code
  • Wini
    Wini about 2 years
    how to change color for tag(prefix value)?
  • Konstantin Konopko
    Konstantin Konopko almost 2 years
    Here prefix is not fixed at the beginning of a text