EditText Values in range - android

I would like to enter the values in a range like 1-60. The EditText shouldn't accept values like 61,62..., or 0,-1,-2...
How can we give the range 1-60 to EditText in android?
I have done in main.xml as
<EditText android:layout_height="wrap_content"
android:id="#+id/editText1"
android:layout_width="160dip"
android:inputType="number">
</EditText>

You can assign a TextWatcher to your EditText and listen for text changes there, for example:
public void afterTextChanged(Editable s) {
try {
int val = Integer.parseInt(s.toString());
if(val > 60) {
s.replace(0, s.length(), "60", 0, 2);
} else if(val < 1) {
s.replace(0, s.length(), "1", 0, 1);
}
} catch (NumberFormatException ex) {
// Do something
}
}
As mentioned by Devunwired, notice that calls to s.replace() will call the TextWatcher again recursively.
It is typical to wrap these changes with a check on a boolean "editing" flag so the recursive calls skip over and simply return while the changes that come from within.

I have come across a neat solution here:
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max) {
this.min = Integer.parseInt(min);
this.max = Integer.parseInt(max);
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) { }
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
And simply apply this filter to an edit text like so:
mCentsEditText = (EditText)v.findViewById(R.id.cents_edit_text);
InputFilterMinMax filter = new InputFilterMinMax("0", "99") {};
mCentsEditText.setFilters(new InputFilter[]{filter});

I fixed Daniel Wilson's solution:
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max) {
this.min = Integer.parseInt(min);
this.max = Integer.parseInt(max);
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
//The commented line below only works if you append/modify the end of the text (not the beginning or middle)
//int input = Integer.parseInt(dest.toString() + source.toString());
//corrected solution below (3lines)
CharSequence part1 = dest.subSequence(0, dstart);
CharSequence part2 = dest.subSequence(dend, dest.length());
int input = Integer.parseInt(part1 + source.toString() + part2);
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) { }
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
Finally add the InputFilter to your EditText control:
mCentsEditText = (EditText)findViewById(R.id.cents_edit_text);
InputFilterMinMax filter = new InputFilterMinMax("1", "60") {};
mCentsEditText.setFilters(new InputFilter[]{filter});

Try this..
EditText.setOnEditorActionListener(new OnEditorActionListener()
{
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
//add your condtion here.
return false;
}
});

Why not use a Seekbar Instead of EditText?
That way, only numbers can be entered and the maximum limit can be specified/modified as and when you need.
public class SeekBar1 extends Activity implements SeekBar.OnSeekBarChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
..
mSeekBar = (SeekBar)findViewById(R.id.seekBar);
mSeekBar.setOnSeekBarChangeListener(this);
..
}
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
//Do your Changes Here
}
public void onStartTrackingTouch(SeekBar seekBar) {
//On First Track Touch
}
public void onStopTrackingTouch(SeekBar seekBar) {
//On Stop Track Touch
}
}
For numerical Input type values, Seekbar is the best possible UI. Although, the precision on it is questionable.

Very interesting question.
I guess the best way to do this is implementing a new inputType, but the setInputType method receives an int. Nothing to do there :(
In that method doc it says:
Set the type of the content with a
constant as defined for inputType.
This will take care of changing the
key listener, by calling
setKeyListener(KeyListener), to match
the given content type.
Excellent, you can provide a keyListener with setKeyListener.
You can extend android.text.method.DigitsKeyListener to create your new keyListener, avoiding the issue with the TextWatcher.

I don't have enough priviledges to comment on Ashok Felix's answer but I'd like to add that I have found some code premitting to display a SeekBar in preferences.
It is very easy to use (I'm not the author). See the SeekBarPreference code by Matthew Wiggins: http://android.hlidskialf.com/blog/code/android-seekbar-preference

This works but not live.
editText.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
try {
int val = Integer.parseInt(editText.getText()
.toString());
if (val > 2000) {
editText.setText("");
} else if (val < 100) {
editText.setText("");
}
} catch (NumberFormatException ex) {
}
}
});

Related

The text of the edittext can't modified [duplicate]

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?
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());
}
}
});
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.
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);
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.
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();
}
}
You had it almost right, try
private final String PREFIX="http://";
editText.setFilters(new InputFilter[]{new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int
dend) {
return dstart<PREFIX.length()?dest.subSequence(dstart,dend):null;
}
}});
CODE TO ADD CUSTOM PREFIX TO YOUR EDITTEXT (PREFIX NOT EDITABLE)
Code from Medium by Ali Muzaffar
public class PrefixEditText extends AppCompatEditText {
float originalLeftPadding = -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 (originalLeftPadding == -1) {
String prefix = (String) getTag();
float[] widths = new float[prefix.length()];
getPaint().getTextWidths(prefix, widths);
float textWidth = 0;
for (float w : widths) {
textWidth += w;
}
originalLeftPadding = getCompoundPaddingLeft();
setPadding((int) (textWidth + originalLeftPadding),
getPaddingRight(), getPaddingTop(),
getPaddingBottom());
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String prefix = (String) getTag();
canvas.drawText(prefix, originalLeftPadding, getLineBounds(0, null), getPaint());
}
}
And XML
<com.yourClassPath.PrefixEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:textSize="14sp"
android:tag="€ " />
An easy to use Kotlin extension function for this purpose
fun EditText.stickPrefix(prefix: String) {
this.addTextChangedListener(afterTextChanged = {
if (!it.toString().startsWith(prefix) && it?.isNotEmpty() == true) {
this.setText(prefix + this.text)
this.setSelection(this.length())
}
})
}
//someEditText.stickPrefix("+")
I know I'm reviving an old post but I want to share with the community that I have struggled with this topic these days and I found that placing a TextView over the EditText is not only perfectly doable (to respond to the second part of the question), much more in this case when the constant text is needed in the starting position, but preferable, too. Moreover the cursor won't even move before the "mutable" text at all, which is an elegant effect.
I prefer this solution because it doesn't add workload and complexity to my app with listeners and whatsoever.
Here's a sample code of my solution:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="3dp"
android:text="http://" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textUri"
android:paddingStart="choose an appropriate padding" />
</RelativeLayout>
By enclosing the views in a RelativeLayout they will be overlapped.
The trick here is playing with the android:paddingStart property of the EditText, to make the text start just right after the TextView, while android:layout_centerVertical="true" and android:layout_marginStart="3dp" properties of the TextView make sure that its text is correctly aligned with text inputted and with the start of the underlying line of the EditText (or at least this happens when using a Material themed one).
I made Kotlin extension function for adding prefix to EditText
fun EditText.addPrefix(prefix: String) {
var text = ""
var isPrefixModified = false
val formattedPrefix = "$prefix "
var lastCharSequence: CharSequence? = null
val setEditText: () -> Unit = {
setText(text)
Selection.setSelection(editableText, text.length)
}
this.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable?) {
val newText = editable.toString()
when {
isPrefixModified -> {
isPrefixModified = false
setEditText()
}
isTryingToDeletePrefix(newText) -> {
setEditText()
}
isNewInput(newText) -> {
text = "$formattedPrefix$newText"
setEditText()
}
else -> {
text = newText
}
}
}
override fun beforeTextChanged(charSequence: CharSequence?, start: Int,
count: Int, after: Int) {
charSequence?.let {
if (it != lastCharSequence && it.isNotEmpty() && start <= prefix.length) {
isPrefixModified = true
}
lastCharSequence = charSequence
}
}
override fun onTextChanged(charSequence: CharSequence?, start: Int,
before: Int, count: Int) {
// Ignore
}
private fun isTryingToDeletePrefix(newText: String) =
text.isNotEmpty() && newText.length < text.length && isNewInput(newText)
private fun isNewInput(newText: String) = !newText.contains(formattedPrefix)
})
}
I just found the solution how to make prefix not-editable and how to save text if you try to remove prefix. That's very close to #Rajitha Siriwardena answer. All you missed is to save text before any changes applied. It will be restored in afterTextChanged(...).
Code:
final String prefix = "http://";
editText.setText(prefix);
Selection.setSelection(editText.getText(), editText.getText().length());
editText.addTextChangedListener(new TextWatcher() {
String text;
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
text = charSequence.toString();
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if (!editable.toString().startsWith(prefix)) {
editText.setText(text);
Selection.setSelection(editText.getText(), editText.getText().length());
}
}
});
This one is basically to add prefix "+91" to your edit text field of phone number.
1.Add this code to oncreate() of activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
// Write other things......//
etPhoneNumber.setFilters(new InputFilter[]{getPhoneFilter(),newInputFilter.LengthFilter(13)});
etPhoneNumber.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (etPhoneNumber.getText().toString().isEmpty()) {
etPhoneNumber.setText("+91");
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length()); }
} else {
if (etPhoneNumber.getText().toString().equalsIgnoreCase("+91")) {
etPhoneNumber.setFilters(new InputFilter[]{});
etPhoneNumber.setText("");
etPhoneNumber.setFilters(new InputFilter[]{getPhoneFilter(),new InputFilter.LengthFilter(13)});
}
}
}
});
}
2.Declare a method called getPhoneFilter()
private InputFilter getPhoneFilter() {
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length());
etPhoneNumber.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
if(!s.toString().startsWith("+91")){
if (etPhoneNumber.getFilters() != null && etPhoneNumber.getFilters().length > 0) {
etPhoneNumber.setText("+91");
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length());
}
}
}
});
// Input filter to restrict user to enter only digits..
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (!String.valueOf(getString(R.string.digits_number)).contains(String.valueOf(source.charAt(i)))) {
return "";
}
}
return null;
}
};
return filter;
}
3.declare "digits_number" in your values file
<string name="digits_number">1234567890+</string>
Based on #demaksee comment. I extend EditText and override function onSelectionChanged. So user even can`t edit prefix. Very simple and useful.
Kotlin:
private var prefix : String? = ""
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
if (prefix != null && prefix!!.isNotBlank()) {
var finalStart = selStart
var finalEnd = selEnd
val prefixLength = prefix!!.length
if (prefixLength > selStart) {
finalStart = prefixLength
}
if (prefixLength > selEnd) {
finalEnd = prefixLength
}
if (finalStart == selStart && finalEnd == selEnd) {
super.onSelectionChanged(finalStart, finalEnd)
} else {
val startWithPrefix = text?.startsWith(prefix ?: "") ?: prefix.isNullOrBlank()
if (!startWithPrefix) {
setText(prefix)
}
setSelection(finalStart, finalEnd)
}
}
}
public fun setPrefix(prefix: String) {
editText.setText(prefix)
editText.setSelection(prefix.length)
this.prefix = prefix
}
Here is a less efficient solution that should handle all cases for when characters OR words are deleted/inserted in OR around the prefix.
prefix = "http://"
extra = "ahhttp://"
differencePrefix(prefix, extra) = "aht"
Code:
public static String differencePrefix(String prefix, String extra) {
if (extra.length() < prefix.length()) return "";
StringBuilder sb = new StringBuilder();
StringBuilder eb = new StringBuilder();
int p = 0;
for (int i = 0; i < extra.length(); i++) {
if (i >= prefix.length()) {
while(p < extra.length()) {
eb.append(extra.charAt(p));
p++;
}
break;
}
if (p >= extra.length()) break;
char pchar = extra.charAt(p);
char ichar = prefix.charAt(i);
while(pchar != ichar) {
//check if char was deleted
int c = i + 1;
if (c < prefix.length()) {
char cchar = prefix.charAt(c);
if (cchar == pchar) {
break;
}
}
sb.append(pchar);
p++;
if (p >= extra.length()) break;
pchar = extra.charAt(p);
}
p++;
}
return eb.toString() + sb.toString();
}
You can use it like this
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
String input = s.toString();
if (!input.startsWith(prefix)) {
String extra = differencePrefix(prefix, input);
String newInput = prefix + extra;
editText.setText(newInput);
editText.setSelection(newInput.length());
}
}
});
EditText msg=new EditText(getContext());
msg.setSingleLine(true);
msg.setSingleLine();
msg.setId(View.generateViewId());
msg.measure(0,0);
TextView count=new TextView(getContext());
count.setTextColor(Color.parseColor("#666666"));
count.setText("20");
count.setPadding(0,0,(int)Abstract.getDIP(getContext(),10),0);
count.measure(0,0);
float tenPIX =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getContext().getResources().getDisplayMetrics());
msg.setPadding((int)tenPIX,(int)tenPIX,(int)(int)tenPIX+count.getMeasuredWidth(),(int)tenPIX);
RelativeLayout ll1=new RelativeLayout(getContext());
ll1.addView(msg,new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
LayoutParams countlp=new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
countlp.addRule(RelativeLayout.ALIGN_END,msg.getId());
countlp.addRule(RelativeLayout.ALIGN_BASELINE,msg.getId());
ll1.addView(count,countlp);
The code below works for me. It handles cases when the user edits the prefix, deletes it, inserts text from the buffer, changes the selected text. If the user changes the prefix, the focus moves to the end of the prefix.
final String prefix = "http://";
final String[] aLastText = {prefix};
et.setText(prefix);
et.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void afterTextChanged(Editable sNew) {
if (!sNew.toString().startsWith(prefix)) {
String sLast = aLastText[0];
boolean isRemoving = sNew.length() < sLast.length();
int start;
int end = sNew.length() - 1;
for (start = 0; start < sLast.length() && start < sNew.length(); start++) {
if (sLast.charAt(start) != sNew.charAt(start))
break;
}
int k = sLast.length() - 1;
for (; end >= start && k >= 0; end--, k--) {
if (sLast.charAt(k) != sNew.charAt(end))
break;
}
String sEdited = sNew.toString().substring(start, ++end);
k += isRemoving ? 1 : 0;
k = k < prefix.length() ? prefix.length() : k;
String sSuffix = sLast.substring(k, sLast.length());
et.setText(prefix + sEdited + sSuffix);
et.setSelection(et.getText().length() - sSuffix.length());
}
aLastText[0] = et.getText().toString();
}
});
Examples:
ht5tp://localhost, 5http://localhost, http:/5/localhost -> http://5localhost
http:localhost -> http://localhost
what worked for me is to add some changes on Rajitha Siriwardena code :
First, put text on the Edittext or TextInputEditText xml layout :
android:text="http://"
the purpose is to test the if condition on the first attempt
Second,
test the condition with if like this
#Override
public void afterTextChanged(Editable s) {
if (!s.toString().startsWith("http://")) {
etPhone.setText("http://");
etPhone.setSelection(etPhone.length());
}
I am baffled by the complex answers posted. More easier way will be to add a textview with code as text as a prefix and put some elevation. This way, you will much finer control over the designing of the code("+91"). Here's an example of the same.
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/mobile_bottom_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/card_with_top_radius"
android:elevation="12dp"
android:paddingBottom="#dimen/dim_18"
app:flow_verticalAlign="bottom"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="#+id/code"
style="#style/color_333333_text_14_roboto_regular_venus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/dim_16"
android:text="+91"
android:elevation="1dp"
app:layout_constraintBottom_toBottomOf="#id/number"
app:layout_constraintStart_toStartOf="#id/number"
app:layout_constraintTop_toTopOf="#id/number" />
<com.gradeup.baseM.view.custom.TabletEditText
android:id="#+id/number"
style="#style/color_333333_text_12_roboto_medium_venus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="#dimen/dim_16"
android:layout_marginTop="#dimen/dim_17"
android:layout_marginBottom="#dimen/dim_16"
android:background="#drawable/e6e6e6_4dp_curved_border_white_bg"
android:hint="#string/enter_mobile_number"
android:imeOptions="flagNoExtractUi"
android:inputType="number"
android:maxLength="10"
android:maxLines="1"
android:paddingVertical="#dimen/dim_17"
android:paddingStart="#dimen/dim_50"
android:paddingEnd="20dp"
android:textColorHint="#color/color_999999_8799ae"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/subTitle">
</com.gradeup.baseM.view.custom.TabletEditText>
</androidx.constraintlayout.widget.ConstraintLayout>
Things to keep in mind :-
Adjust editText paddingStart attribute according to your need.
Put some elevation in code TextView.

How to force decimal point after two digit in edittext?

How can I set the fractional point after two integers in android and set the limit to 55 digits only? After searching a lot I am posting my problem here. I have an Edittext with an android:inputType="number" . I am able to set max limit to the EditText to 55 digits. I want user can able to type fractional digit also between 0 to 55 digits like 24.22 or 52.88.
Can some please tell me how can I achieve this?
Here is my code.
public class FuelCostCalculator extends DialogFragment {
EditText etLocation, etKilo, etLiter, etFuelCost;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, R.style.fullscreen_dialog);
}
private void init(View view) {
//this is my editText
etLiter = view.findViewById(R.id.etLiter);
InputFilterMinMax filter = new InputFilterMinMax("0", "5499") {};
etLiter.setFilters(new InputFilter[]{filter});
}
}
My Filter class is :
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max) {
this.min = Integer.parseInt(min);
this.max = Integer.parseInt(max);
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) { }
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
Any kind of help is appreciated :
Check this answer . Though it is not so much clean but it will work as per your needs. Assuming that actAddItemFromDropdownList is your edit text and you have set maximum digits limit in your Xml.
int max =0;
String text ="";
actAddItemFromDropdownList.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if(actAddItemFromDropdownList.getText().length()>0){
if(text.equals(actAddItemFromDropdownList.getText().toString())){
text = "";
}else {
text = actAddItemFromDropdownList.getText().toString();
max = max + 1;
if (max == 2) {
text = text + ".";
max = 0;
actAddItemFromDropdownList.setText(text);
actAddItemFromDropdownList.setSelection(actAddItemFromDropdownList.getText().length());
}
}
}
}
});
try it and if it works mark as selected answer.

limiting values of edittext to certain values in android

I am using edit text in my code.I need to limit the weight value to 160 .How to achieve this.
This is the XML I'm using
android:id="#+id/txtWeight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:inputType="number"
android:layout_weight="0"
android:background="#drawable/border"
android:padding="5dp"
android:maxLength="3"
android:textSize="15sp"
android:maxLines="1"
android:hint=""
i have taken maxLenght as "3". So user will have option of entering upto 999 . I need to limit to 160.
Do this
InputFilter if = new InputFilter[]{ new InputFilterMinMax("0", "180")}
or customize it
InputFilter filterTwoDecimal = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
return null;
}
};
Try this:
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max) {
this.min = Integer.parseInt(min);
this.max = Integer.parseInt(max);
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) { }
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
Then on your fragment / activity:
EditText et = (EditText) findViewById(R.id.myEditText);
et.setFilters(new InputFilter[]{ new InputFilterMinMax("1", "180")});
You can add a TextWatcher to your EditText and make changes to it so it won't allow unwanted values
editText.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) {
// TODO Auto-generated method stub
}
});

set the range of numbers from 2 to 1000 in an edit text box in android

In My application I have an edit text box in which user is allowed to enter numbers only from 2 to 1000. I have already implemented the validation for this,,
Eg. if the number entered in lesser than "2" set-text should be "2"and i am saving these values in a shared preference file on click of button and retaining these input values for further use.
Here is problem occurring when user is entering any number more than 1000 or less than 2, and press the phone's back key than click on the button,it saves the incorrect values which are even not allowed.
I have also implemented the back pressed() method but if the keypad is up,,I m still able to use the back key. I am trying to do something where user will even not be able to enter any number which is more than 1000. Either keypad stops working or it get disable,something like this,that the edit text box even don't take any incorrect value..
in short I want to set a range of numbers that a edit text box can take a input.
please help
Instead of button click validation ,you can use Textwatcher
http://developer.android.com/reference/android/text/TextWatcher.html
example
editext1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// YOur Code
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
First make this class :
package com.test;
import android.text.InputFilter;
import android.text.Spanned;
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max) {
this.min = Integer.parseInt(min);
this.max = Integer.parseInt(max);
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) { }
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
Then use this from your Activity :
EditText et = (EditText) findViewById(R.id.myEditText);
et.setFilters(new InputFilter[]{ new InputFilterMinMax("1", "12")});
This will allow user to enter values from 1 to 12 only.
EDIT :
Set your edittext with android:inputType="number".
Thanks.
You can disable the keyboard like this:
InputMethodManager ipmm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ipmm.hideSoftInputFromWindow(url.getWindowToken(), 0);
Where url is :
url = (EditText) findViewById(R.id.eT_webbrowser);

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

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?
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());
}
}
});
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.
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);
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.
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();
}
}
You had it almost right, try
private final String PREFIX="http://";
editText.setFilters(new InputFilter[]{new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int
dend) {
return dstart<PREFIX.length()?dest.subSequence(dstart,dend):null;
}
}});
CODE TO ADD CUSTOM PREFIX TO YOUR EDITTEXT (PREFIX NOT EDITABLE)
Code from Medium by Ali Muzaffar
public class PrefixEditText extends AppCompatEditText {
float originalLeftPadding = -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 (originalLeftPadding == -1) {
String prefix = (String) getTag();
float[] widths = new float[prefix.length()];
getPaint().getTextWidths(prefix, widths);
float textWidth = 0;
for (float w : widths) {
textWidth += w;
}
originalLeftPadding = getCompoundPaddingLeft();
setPadding((int) (textWidth + originalLeftPadding),
getPaddingRight(), getPaddingTop(),
getPaddingBottom());
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String prefix = (String) getTag();
canvas.drawText(prefix, originalLeftPadding, getLineBounds(0, null), getPaint());
}
}
And XML
<com.yourClassPath.PrefixEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:textSize="14sp"
android:tag="€ " />
An easy to use Kotlin extension function for this purpose
fun EditText.stickPrefix(prefix: String) {
this.addTextChangedListener(afterTextChanged = {
if (!it.toString().startsWith(prefix) && it?.isNotEmpty() == true) {
this.setText(prefix + this.text)
this.setSelection(this.length())
}
})
}
//someEditText.stickPrefix("+")
I know I'm reviving an old post but I want to share with the community that I have struggled with this topic these days and I found that placing a TextView over the EditText is not only perfectly doable (to respond to the second part of the question), much more in this case when the constant text is needed in the starting position, but preferable, too. Moreover the cursor won't even move before the "mutable" text at all, which is an elegant effect.
I prefer this solution because it doesn't add workload and complexity to my app with listeners and whatsoever.
Here's a sample code of my solution:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="3dp"
android:text="http://" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textUri"
android:paddingStart="choose an appropriate padding" />
</RelativeLayout>
By enclosing the views in a RelativeLayout they will be overlapped.
The trick here is playing with the android:paddingStart property of the EditText, to make the text start just right after the TextView, while android:layout_centerVertical="true" and android:layout_marginStart="3dp" properties of the TextView make sure that its text is correctly aligned with text inputted and with the start of the underlying line of the EditText (or at least this happens when using a Material themed one).
I made Kotlin extension function for adding prefix to EditText
fun EditText.addPrefix(prefix: String) {
var text = ""
var isPrefixModified = false
val formattedPrefix = "$prefix "
var lastCharSequence: CharSequence? = null
val setEditText: () -> Unit = {
setText(text)
Selection.setSelection(editableText, text.length)
}
this.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable?) {
val newText = editable.toString()
when {
isPrefixModified -> {
isPrefixModified = false
setEditText()
}
isTryingToDeletePrefix(newText) -> {
setEditText()
}
isNewInput(newText) -> {
text = "$formattedPrefix$newText"
setEditText()
}
else -> {
text = newText
}
}
}
override fun beforeTextChanged(charSequence: CharSequence?, start: Int,
count: Int, after: Int) {
charSequence?.let {
if (it != lastCharSequence && it.isNotEmpty() && start <= prefix.length) {
isPrefixModified = true
}
lastCharSequence = charSequence
}
}
override fun onTextChanged(charSequence: CharSequence?, start: Int,
before: Int, count: Int) {
// Ignore
}
private fun isTryingToDeletePrefix(newText: String) =
text.isNotEmpty() && newText.length < text.length && isNewInput(newText)
private fun isNewInput(newText: String) = !newText.contains(formattedPrefix)
})
}
I just found the solution how to make prefix not-editable and how to save text if you try to remove prefix. That's very close to #Rajitha Siriwardena answer. All you missed is to save text before any changes applied. It will be restored in afterTextChanged(...).
Code:
final String prefix = "http://";
editText.setText(prefix);
Selection.setSelection(editText.getText(), editText.getText().length());
editText.addTextChangedListener(new TextWatcher() {
String text;
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
text = charSequence.toString();
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if (!editable.toString().startsWith(prefix)) {
editText.setText(text);
Selection.setSelection(editText.getText(), editText.getText().length());
}
}
});
This one is basically to add prefix "+91" to your edit text field of phone number.
1.Add this code to oncreate() of activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
// Write other things......//
etPhoneNumber.setFilters(new InputFilter[]{getPhoneFilter(),newInputFilter.LengthFilter(13)});
etPhoneNumber.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (etPhoneNumber.getText().toString().isEmpty()) {
etPhoneNumber.setText("+91");
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length()); }
} else {
if (etPhoneNumber.getText().toString().equalsIgnoreCase("+91")) {
etPhoneNumber.setFilters(new InputFilter[]{});
etPhoneNumber.setText("");
etPhoneNumber.setFilters(new InputFilter[]{getPhoneFilter(),new InputFilter.LengthFilter(13)});
}
}
}
});
}
2.Declare a method called getPhoneFilter()
private InputFilter getPhoneFilter() {
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length());
etPhoneNumber.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
if(!s.toString().startsWith("+91")){
if (etPhoneNumber.getFilters() != null && etPhoneNumber.getFilters().length > 0) {
etPhoneNumber.setText("+91");
Selection.setSelection(etPhoneNumber.getText(), etPhoneNumber.getText().length());
}
}
}
});
// Input filter to restrict user to enter only digits..
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (!String.valueOf(getString(R.string.digits_number)).contains(String.valueOf(source.charAt(i)))) {
return "";
}
}
return null;
}
};
return filter;
}
3.declare "digits_number" in your values file
<string name="digits_number">1234567890+</string>
Based on #demaksee comment. I extend EditText and override function onSelectionChanged. So user even can`t edit prefix. Very simple and useful.
Kotlin:
private var prefix : String? = ""
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
if (prefix != null && prefix!!.isNotBlank()) {
var finalStart = selStart
var finalEnd = selEnd
val prefixLength = prefix!!.length
if (prefixLength > selStart) {
finalStart = prefixLength
}
if (prefixLength > selEnd) {
finalEnd = prefixLength
}
if (finalStart == selStart && finalEnd == selEnd) {
super.onSelectionChanged(finalStart, finalEnd)
} else {
val startWithPrefix = text?.startsWith(prefix ?: "") ?: prefix.isNullOrBlank()
if (!startWithPrefix) {
setText(prefix)
}
setSelection(finalStart, finalEnd)
}
}
}
public fun setPrefix(prefix: String) {
editText.setText(prefix)
editText.setSelection(prefix.length)
this.prefix = prefix
}
Here is a less efficient solution that should handle all cases for when characters OR words are deleted/inserted in OR around the prefix.
prefix = "http://"
extra = "ahhttp://"
differencePrefix(prefix, extra) = "aht"
Code:
public static String differencePrefix(String prefix, String extra) {
if (extra.length() < prefix.length()) return "";
StringBuilder sb = new StringBuilder();
StringBuilder eb = new StringBuilder();
int p = 0;
for (int i = 0; i < extra.length(); i++) {
if (i >= prefix.length()) {
while(p < extra.length()) {
eb.append(extra.charAt(p));
p++;
}
break;
}
if (p >= extra.length()) break;
char pchar = extra.charAt(p);
char ichar = prefix.charAt(i);
while(pchar != ichar) {
//check if char was deleted
int c = i + 1;
if (c < prefix.length()) {
char cchar = prefix.charAt(c);
if (cchar == pchar) {
break;
}
}
sb.append(pchar);
p++;
if (p >= extra.length()) break;
pchar = extra.charAt(p);
}
p++;
}
return eb.toString() + sb.toString();
}
You can use it like this
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
String input = s.toString();
if (!input.startsWith(prefix)) {
String extra = differencePrefix(prefix, input);
String newInput = prefix + extra;
editText.setText(newInput);
editText.setSelection(newInput.length());
}
}
});
EditText msg=new EditText(getContext());
msg.setSingleLine(true);
msg.setSingleLine();
msg.setId(View.generateViewId());
msg.measure(0,0);
TextView count=new TextView(getContext());
count.setTextColor(Color.parseColor("#666666"));
count.setText("20");
count.setPadding(0,0,(int)Abstract.getDIP(getContext(),10),0);
count.measure(0,0);
float tenPIX =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getContext().getResources().getDisplayMetrics());
msg.setPadding((int)tenPIX,(int)tenPIX,(int)(int)tenPIX+count.getMeasuredWidth(),(int)tenPIX);
RelativeLayout ll1=new RelativeLayout(getContext());
ll1.addView(msg,new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
LayoutParams countlp=new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
countlp.addRule(RelativeLayout.ALIGN_END,msg.getId());
countlp.addRule(RelativeLayout.ALIGN_BASELINE,msg.getId());
ll1.addView(count,countlp);
The code below works for me. It handles cases when the user edits the prefix, deletes it, inserts text from the buffer, changes the selected text. If the user changes the prefix, the focus moves to the end of the prefix.
final String prefix = "http://";
final String[] aLastText = {prefix};
et.setText(prefix);
et.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void afterTextChanged(Editable sNew) {
if (!sNew.toString().startsWith(prefix)) {
String sLast = aLastText[0];
boolean isRemoving = sNew.length() < sLast.length();
int start;
int end = sNew.length() - 1;
for (start = 0; start < sLast.length() && start < sNew.length(); start++) {
if (sLast.charAt(start) != sNew.charAt(start))
break;
}
int k = sLast.length() - 1;
for (; end >= start && k >= 0; end--, k--) {
if (sLast.charAt(k) != sNew.charAt(end))
break;
}
String sEdited = sNew.toString().substring(start, ++end);
k += isRemoving ? 1 : 0;
k = k < prefix.length() ? prefix.length() : k;
String sSuffix = sLast.substring(k, sLast.length());
et.setText(prefix + sEdited + sSuffix);
et.setSelection(et.getText().length() - sSuffix.length());
}
aLastText[0] = et.getText().toString();
}
});
Examples:
ht5tp://localhost, 5http://localhost, http:/5/localhost -> http://5localhost
http:localhost -> http://localhost
what worked for me is to add some changes on Rajitha Siriwardena code :
First, put text on the Edittext or TextInputEditText xml layout :
android:text="http://"
the purpose is to test the if condition on the first attempt
Second,
test the condition with if like this
#Override
public void afterTextChanged(Editable s) {
if (!s.toString().startsWith("http://")) {
etPhone.setText("http://");
etPhone.setSelection(etPhone.length());
}
I am baffled by the complex answers posted. More easier way will be to add a textview with code as text as a prefix and put some elevation. This way, you will much finer control over the designing of the code("+91"). Here's an example of the same.
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/mobile_bottom_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/card_with_top_radius"
android:elevation="12dp"
android:paddingBottom="#dimen/dim_18"
app:flow_verticalAlign="bottom"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="#+id/code"
style="#style/color_333333_text_14_roboto_regular_venus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/dim_16"
android:text="+91"
android:elevation="1dp"
app:layout_constraintBottom_toBottomOf="#id/number"
app:layout_constraintStart_toStartOf="#id/number"
app:layout_constraintTop_toTopOf="#id/number" />
<com.gradeup.baseM.view.custom.TabletEditText
android:id="#+id/number"
style="#style/color_333333_text_12_roboto_medium_venus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="#dimen/dim_16"
android:layout_marginTop="#dimen/dim_17"
android:layout_marginBottom="#dimen/dim_16"
android:background="#drawable/e6e6e6_4dp_curved_border_white_bg"
android:hint="#string/enter_mobile_number"
android:imeOptions="flagNoExtractUi"
android:inputType="number"
android:maxLength="10"
android:maxLines="1"
android:paddingVertical="#dimen/dim_17"
android:paddingStart="#dimen/dim_50"
android:paddingEnd="20dp"
android:textColorHint="#color/color_999999_8799ae"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/subTitle">
</com.gradeup.baseM.view.custom.TabletEditText>
</androidx.constraintlayout.widget.ConstraintLayout>
Things to keep in mind :-
Adjust editText paddingStart attribute according to your need.
Put some elevation in code TextView.

Categories

Resources