TextWatcher works but after text changed not - android

This is my text watcher to control user's birth year enter. If user enters less than 1900 I want to replace it with 1900. App works properly. I can enter a value to TextView. But when start typing starts with "1" then immediately replacing to "1900" after I can't edit TextView again. Delete button on keypad does not delete entered value.
#Override
public void afterTextChanged(Editable s) {
try {
int birth = Integer.parseInt(s.toString());
if (birth < 1900) {
s.replace(0, s.length(), "1900");
}
} catch (NumberFormatException e) {
}
}
<EditText
android:id="#+id/editText1"
android:hint="Birth Year"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberSigned">
</EditText>

Alright my Friend i've been thinking about it for a while here is the closest solution i could get. try this
#Override
public void afterTextChanged(Editable s) {
try {
int birth = Integer.parseInt(s.toString());
if (birth < 1900 && s.length()>=4) {
s.replace(0, s.length(), "1900");
}
} catch (NumberFormatException e) {
}
}
This is only a small modification on your if statement.

replacing to "1900" after I can't edit TextView again. Delete button on keypad does not delete entered value.
This is expected behavior, It doesn't mean that delete button on keyboard does not delete the reentered value, Since after you replace the 1 to 1900 and then try to delete 0 (the last digit) will be deleted and immediately afterTextChanged will be called with input 190, so your condition again satisfies to <1900 and the text is replace with 1900 again (this continues when you try to delete) .
I would suggest to add a check to see the minimum length of the input , I believe you expect the user to enter at least 4 digit.
public void afterTextChanged(Editable s) {
if(s.toString().length < 4) {
return;
}
// do your other logic here
}

Related

how to save Editable s value in afterTextChanged?

I am going to save the value in one textview after the length of input string is fulfilled. but saved value is empty if the value of textview is used. If Editable s value in afterTextChanged is used, it causes crash.
Some codes as following:
number = (EditText) findViewById(R.id.number);
final String numberStr = number.getText().toString();
if following afterTextChanged is used, empty value is saved even I already input sth.
#Override
public void afterTextChanged(Editable s) {
if (s.length() == 11) {
Toast.makeText(MainActivity.this, numberStr , Toast.LENGTH_SHORT).show();
saveSettingNote(MainActivity.this, "number_save", "number", numberStr);
number.setText(getSettingNote(MainActivity.this,"number_save", "number"));
}
}
if following code is used, it will cause crash:
#Override
public void afterTextChanged(Editable s) {
if (s.length() == 11) {
Toast.makeText(MainActivity.this, s.toString(), Toast.LENGTH_SHORT).show();
saveSettingNote(MainActivity.this, "number_save", "number", s.toString());
number.setText(getSettingNote(MainActivity.this,"number_save", "number"));
}
}
Saving and getting are based on SharedPreferences, which works well in other situation.
Actually, what I want to implement is saving String after the criteria is fulfilled for input string.
Please help to identify what is wrong in above code or suggest a new to get that function. Thanks a lot in advance.
Your app is crashing because your listener is looping indefinitely with the same value passed in over and over.
The ugly truth is that you've to unbind your listener, set the value and then bind it again:
#Override
public void afterTextChanged(Editable s) {
if (s.length() == 11) {
// unbind your listener
editText.addTextChangedListener(null);
// do your stuff
Toast.makeText(MainActivity.this, s.toString(), Toast.LENGTH_SHORT).show();
saveSettingNote(MainActivity.this, "number_save", "number", s.toString());
number.setText(getSettingNote(MainActivity.this,"number_save", "number"));
// bind your listener again
editText.addTextChangedListener(MainActivity.this);
}
}
Using RxBinding you can achieve this in a more elegant way:
RxTextView.textChanges(editText)
.map { it.toString() }
.filter({ it.length == 11 })
.distinctUntilChanged() // <-- the important part
.subscribe(
{ s -> /* do your stuff here */}
)
you set text in editext afterTextChanged(Editable s) which calls text change listener again and again and cause the application to crash. call number.setText(getSettingNote(MainActivity.this,"number_save", "number")); outside the text change listener.
My guess it that by declaring numberStr as you did, you expect to change its value each time the edit text change its content. However, this is not the case; it will be initialised with an empty string "" (unless you don't have any other string in the edit text at that moment) and then it will NEVER change its value, thus resulting in the empty value that you save. As solution I would suggest to make numberStr non final and update its value (like you already did) each time before showing the Toast.

How to check value in edit text while entering text in android?

I have a edit text field named as mobile and password and Scenario is that when app launch it appears with error text ,what I want when enter a text in respective field and after completing editing text check with value if correct then move else show error in that field.
code:-
private final BroadcastReceiver m_oOtpReceiver = new BroadcastReceiver() {// creating broadcast to receive otp sent by server from Inbox...
#Override
public void onReceive(Context context, Intent intent) {// on receive method to read OTP sent by server
checkFieldsForEmpty(true);// check whether edit text is empty or not
}
};
private TextWatcher m_oTextWatcher = new TextWatcher() {// making object of TextWathcher class
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {// when text change in Edit tEXT
}
#Override
public void afterTextChanged(Editable s) {
checkFieldsForEmpty(false);// CHECK LOGIN BUTTON DISABLED AND ENABED
}
};
/*This method check Edit text is empty or not*/
public void checkFieldsForEmpty(boolean fromBroadcast) {// this method check Edit text is empty or not
s_szMobileNumber = m_InputMobile.getText().toString().trim();// get mobile number from edit Text
s_szPassword = m_InputPassword.getText().toString().trim();// get password from edit text
if (NetworkUtil.isConnected(getApplicationContext())) {
// if mobile number and password are Emoty
if (s_szMobileNumber != null && s_szMobileNumber.length() > 7 && s_szMobileNumber.length() < 15) {// check if mobile and password is empty ..
if (s_szPassword.length() >= 4 && s_szPassword.length() <= 8) {
m_LoginBtn.setEnabled(true);// make Login button disabled
m_LoginBtn.setBackgroundColor(Color.rgb(0, 80, 147));// set background color on eabled
m_LoginBtn.setOnClickListener(new View.OnClickListener() {// onclick listener on Login Button
#Override
public void onClick(View v) {
postLoginDataToServer();
}
});
} else {
if (!fromBroadcast) {
m_InputPassword.setError("Password must be between 4 to 8 characters long");
}
m_LoginBtn.setEnabled(false);// make login button enabled
m_LoginBtn.setBackgroundColor(Color.rgb(192, 192, 192));// color of login button
}
} else {
if (!fromBroadcast) {
m_InputMobile.setError("Mobile number must be between 7 to 15 characters long");
}
m_LoginBtn.setEnabled(false);// make login button enabled
m_LoginBtn.setBackgroundColor(Color.rgb(192, 192, 192));// color of login button
}
} else {
try {
CSnackBar.getInstance().showSnackBarError(findViewById(R.id.mainLayout), "No Internet Connection Available", getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
m_LoginBtn.setEnabled(false);
m_LoginBtn.setBackgroundColor(Color.rgb(192, 192, 192));
}
}
I can't see where the boolean "fromBroadcast" is either initialised or gets it's state from to know whether that is what you need to check before setting the error message on the textView. From what I have read I would assume you don't need to use an if statement to check "fromBroadcast". The code should work without it. If you are starting the app with an error message and you dont want the error msg then you should check s_szPassword instead of m_InputPassword for input and you can initialise s_szPassword to contain the correct word first so the error msg is not there at the start.

setText() in afterTextChanged() shows the text in reverse order

My code:
fractionNumEt.addTextChangedListener(new TextWatcher() {
boolean ignoreChange = false;
#Override
public void afterTextChanged(Editable s) {
if(!ignoreChange) {
String string = String.valueOf(s);
if (string.length() > 2) {
string = string.substring(0, string.length() - 1);
ignoreChange = true;
fractionNumEt.setText(string);
ignoreChange = false;
}
}
}
....
I am trying to limit the characters to length 2, but want to keep listening. When I type '1','2', it displays "12" which is fine. Now when I type '3', it writes "31" instead of "23".
What on earth is going on!
I also tried:
string = string.substring(1, string.length());
in this case it works for the first time only n then nothing is changed.
This is happening because after setText(), EditText's cursor returns to first position. Then, any new number will be added at the begging of the String.
Try to update your code as follows:
#Override
public void afterTextChanged(Editable s) {
if(!ignoreChange) {
String string = String.valueOf(s);
if (string.length() > 2) {
string = string.substring(0, string.length() - 1);
ignoreChange = true;
fractionNumEt.setText(string);
fractionNumEt.setSelection(fractionNumEt.getText().length());
ignoreChange = false;
}
}
}
Just a suggestion
Check Editable Docs HERE
I think you don't need to convert it to String. afterTextChanged(Editable s) receives a Editable as argument. You can change it directly. Don't need to covert it to a String.
Moreover: You don't even need to make EditText.setText() because any change in the editable, will be passed automatically to EditText (since afterTextChanged is called by android and give you a chance to update the text few moments before to effectively display that text in the EditText).
Maybe, something like that:
#Override
public void afterTextChanged(Editable s) {
if(!ignoreChange) {
if(s.length() > 2) {
s.delete(s.length() - 1,s.length());
}
}
}
Play a little bit with Editable and you will see that it is easier.

EditText.setText()/getText() appears to be too slow to be used in TextWatcher

I have a TextWatcher that adds a dollar sign in front of an EditText value (it's a price field). Everything works fine except that if you type two first digits fast enough, the second digit won't appear. Once you past the first two digits it's all fine. If you type them slowly (almost a second in between) it also works fine.
Here is the TextWatcher code I am using:
#AfterTextChange(R.id.add_itemPrice) // android annotations way
void addDollar(Editable e) {
if (priceFieldBeingModified) {
return;
}
if (!e.toString().startsWith(CURRENCY_SYMB)) {
priceFieldBeingModified = true;
String newValue = CURRENCY_SYMB + e;
priceField.setText(newValue);
if (priceField.getSelectionStart() == 0) {
// move the cursor to the end
priceField.setSelection(priceField.getText().length());
}
priceFieldBeingModified = false;
}
}
priceField EditText has fixed layout_width/layout_height (in dp). From what I can gather, setText()/getText() are just too expensive but I don't know how to avoid them in this case.
priceField.getText().insert(0, CURRENCY_SYMB) doesn't do anything for some reason.
EDIT:
Looks like the problem only happens on Android 4.3 (or an Xperia Z phone). Tried a 4.1 phone - works like a charm.
Any suggestions would be appreciated, I am out of ideas with this one!
This is working fine for me:
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
if(s.toString().equalsIgnoreCase(""))
{
}
else if (!s.toString().startsWith("$")) {
priceFieldBeingModified = true;
String newValue = "$" + s;
e.setText(newValue);
if (e.getSelectionStart() == 0) {
// move the cursor to the end
e.setSelection(e.getText().length());
}
priceFieldBeingModified = false;
}
It checks if string is not null and it doesn't start with "$", then it adds "$" at start and moves cursor to end.

User input shouldn't exceed a particular number entered in edittext in android

Am developing a hymn app in android, is there a way to let users know that the number they have entered cannot be found in the database, thus the hymn index they entered the hymn is not up to that number immediately the entered it in the edit text.
This is a section of the code
android:ems="10"
android:inputType="number"
android:maxLength="3"`
Restricting length of the EditText could work if your value is inside [-99;999].
Anyway you should read and then validate the number.
EditText.
a. If you have a button (user enters hymn number and clicks a button to find), then add something like this in your onClick method:
Editable e = yourEditText.getText();
String hymnNumberInString = "";
if (e != null) s = hymnNumberInString.toString();
if (hymnNumber.isEmpty()) showEmptyAlert(); //show alert that string is empty;
try {
Integer hymnNumber = Integer.valueOf(s);
if (!findHymn(hymnNumber)) {//here is a search
showErrorMessage();
}
} catch (NumberFormatException e) {
e.printStackTrace();
showErrorMessage();
}
b. If you do not have a button, you can add a TextWatcher and show error if hymn number is exceeded:
yourEditText.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (s != null && s.length() != 0) {
try {
Integer hymnNumber = Integer.valueOf(s);
if (findHymn(hymnNumber)) {
//everything is ok, do what you want with it
// BUT!!! Remember that user might entered only 1 and is still entering!
// To ensure that user already entered (or maybe already entered) you can wait for 2 sec.
//E.g. by using someHandler.postDelayed(runnableWithThisCodeInside, 2000);
} else {
showErrorMessage();
}
} catch (NumberFormatException e) {
e.printStackTrace();
showErrorMessage();
}
}
}
});
c. You can use this nice library to simplify proccess of validation.
For predefined set of numbers you can use NumberPicker. This component takes a String array as input (via setDisplayedValues()) - so you can populate it with numbers/string from the database. And its editable (unless you restrict it) - so your user can still enter the number he wants.
is there a way to let users know that the number they have entered cannot be found in the database.
Yes you can do that,Considering you are using EditText to let user enter the number, get the text from there like below
EditText mEdit = (EditText)findViewById(R.id.edittext);
Integer number=Integer.valueOf(editText.getText.toString());
Now you have the number you can run a query on database table to match against the corresponding values, whether it exists in database or not.Something like this
int count= SELECT count(*) FROM tbl_user
WHERE name = ' + number + '
if(count>0){
Log.d("Count","Value exist in database");
}

Categories

Resources