Values of EditText fields are changed depends on each other - java

I'm trying to build temperature converter (F -> C and C -> F).
I have 2 ET fields. when user types in one, the other displays converted value and vice verse.
I understand that similar programs has been build already, but I couldn't find solution.
It works fine for one field, but app closes when I try to edit the other one.
Here is my piece of code:
public class Temp extends Activity implements OnClickListener, OnFocusChangeListener {
private EditText temp_f, temp_c;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.temp);
temp_f = (EditText) findViewById(R.id.temp_f_inp);
temp_c = (EditText) findViewById(R.id.temp_c_inp);
temp_c.setOnFocusChangeListener((OnFocusChangeListener) this);
temp_f.setOnFocusChangeListener((OnFocusChangeListener) this);
}
private TextWatcher tempc = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (temp_c.getText().length() == 0)
{
temp_f.setText("");
} else {
float convValue = Float.parseFloat(temp_c.getText()
.toString());
conv_f = ((convValue - 32) * 5 / 9);
temp_f.setText(String.valueOf(new DecimalFormat(
"##.###").format(conv_f)));
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void afterTextChanged(Editable s) {
}
};
private TextWatcher tempf = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,int before, int count) {
// TODO Auto-generated method stub
if (temp_f.getText().length() == 0)
{
temp_c.setText("");
} else {
float convValue = Float.parseFloat(temp_f.getText()
.toString());
conv_c = ((convValue * 9) / 5 + 32);
temp_c.setText(String.valueOf(new DecimalFormat(
"##.###").format(conv_c)));
}
#Override
public void beforeTextChanged(CharSequence s, int start,int count, int after) {}
#Override
public void afterTextChanged(Editable s) {
}
};
#Override
public void onFocusChange(View v, boolean hasFocus) {
if ((v == findViewById(R.id.temp_c_inp)) && (hasFocus==true)) {
temp_c.addTextChangedListener(tempc);
}
else if((v == findViewById(R.id.temp_f_inp)) && (hasFocus==true)){
temp_f.addTextChangedListener(tempf);
}
}
it seems like onTextChanged still holds the values of the first ET that has been modified and when I try to edit the other ET fields, it throws an error.
Any help would be greatly appreciated!
Thank you!

You could try this:
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (v.equals(findViewById(R.id.temp_c_inp))) {
if(hasFocus){
temp_c.addTextChangedListener(tempc);
}else{
temp_c.removeTextChangedListener(tempc);
}
}
else if(v.equals(findViewById(R.id.temp_f_inp))){
if(hasFocus){
I temp_f.addTextChangedListener(tempf);
}else{
temp_f.removeTextChangedListener(tempf);
}
}
}
I haven't tried the code by myself, but I hope it could help you

Logic seems to be a problem.
What I would do is,
1. On text change, do nothing (or just check for valid input values)
2. On focus change, do conversion and populate other text field.
Also, you have some #Override functions which are essentially null functions. Why override?

Related

Android Studio: Adding two numbers wihout a button

I'm using Android Studio to develop a program which adds two numbers. First, I used a button to start the calculation but now I don't want to use that button anymore so I'm searching for a possibility to add two numbers in real time. If I change one number, the result should appear instantly. Do you have any suggestions?
This is my code für the button variant:
New code:
public class MainActivity extends AppCompatActivity {
EditText firstNumEditText, secondNumEditText;
TextView resultTextView;
class MyTextWatcher implements 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 second = secondNumEditText.getText().toString().trim();
String first = firstNumEditText.getText().toString().trim();
int num1 = Integer.parseInt(second);
int num2 = Integer.parseInt(first);
int result = num1 + num2;
resultTextView.setText(result + "");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firstNumEditText = (EditText) findViewById(R.id.firstNumEditText);
firstNumEditText.addTextChangedListener(new MyTextWatcher());
secondNumEditText = (EditText) findViewById(R.id.secondNumEditText);
secondNumEditText.addTextChangedListener(new MyTextWatcher());
resultTextView = (TextView) findViewById(R.id.resultTextView);
}
}
LogCat's output:
java.lang.NumberFormatException: For input string: ""
at java.lang.Integer.parseInt(Integer.java:533)
at java.lang.Integer.parseInt(Integer.java:556)
at com.example.aufgabe2.MainActivity$MyTextWatcher.afterTextChanged(MainActivity.java:33)
at android.widget.TextView.sendAfterTextChanged(TextView.java:8202)
at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:10381)
at android.text.SpannableStringBuilder.sendAfterTextChanged(SpannableStringBuilder.java:1218)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:579)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:509)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:508)
at android.text.method.NumberKeyListener.onKeyDown(NumberKeyListener.java:121)
at android.widget.TextView.doKeyDown(TextView.java:6284)
at android.widget.TextView.onKeyDown(TextView.java:6074)
at android.view.KeyEvent.dispatch(KeyEvent.java:2676)
at android.view.View.dispatchKeyEvent(View.java:9880)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1667)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1667)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1667)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1667)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1667)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1667)
at com.android.internal.policy.DecorView.superDispatchKeyEvent(DecorView.java:403)
at com.android.internal.policy.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1800)
at androidx.core.view.KeyEventDispatcher.activitySuperDispatchKeyEventPre28(KeyEventDispatcher.java:130)
at androidx.core.view.KeyEventDispatcher.dispatchKeyEvent(KeyEventDispatcher.java:87)
at androidx.core.app.ComponentActivity.dispatchKeyEvent(ComponentActivity.java:126)
at androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:535)
at androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:59)
at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent(AppCompatDelegateImpl.java:2533)
at com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:317)
at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4327)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4298)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3849)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3902)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3868)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3995)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3876)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4052)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3849)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3902)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3868)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3876)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3849)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6210)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6184)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6145)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3647)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
TextWatcher can help you dynamically get value from EditTexts:
I added an inner class to implement TextWatcher
Passed an Object from that inner class to editText.addOnTextChangedListener
I used afterTextChanged() to get result from both EditText and perform my operation.
public class MainActivity extends AppCompatActivity {
private EditText firstNumEditText, secondNumEditText;
private TextView resultTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firstNumEditText= findViewById(R.id.firstNumEditText);
firstNumEditText.addTextChangedListener(new MyTextWatcher());
secondNumEditText=(EditText) findViewById(R.id.secondNumEditText);
secondNumEditText.addTextChangedListener(new MyTextWatcher());
resultTextView=(TextView) findViewById(R.id.resultTextView);
...
}
class MyTextWatcher implements 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 second = secondNumEditText.getText().toString().trim();
String first = firstNumEditText.getText().toString().trim();
if (!second.isEmpty() && !first.isEmpty()) {
try {
int firstNumber = Integer.parseInt(first);
int secondNumber = Integer.parseInt(second);
//Do calculation
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
You could use TextWatcher on your EditText to listen the text change event and perform action like Add or Minus.
You can do it by adding addTextChangedListener to the editText.
editText.addTextChangeListener(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) {
// here you can extract the value from edit text and do the addition
}
#Override
public void afterTextChanged(Editable s) {
}
});

How to add number separators in EditText

I have an Edittext and want to set the EditText so that when the user is inputting the number to be converted, a thousand separator (,) should be added automaticaaly in realtime to the number .but i want do this in "onTextChanged" method not in the "afterTextChanged" method. How can I?
public class NumberTextWatcherForThousand implements TextWatcher {
EditText editText;
public NumberTextWatcherForThousand(EditText editText) {
this.editText = editText;
}
#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 view) {
String s = null;
try {
// The comma in the format specifier does the trick
s = String.format("%,d", Long.parseLong(view.toString()));
edittext.settext(s);
} catch (NumberFormatException e) {
}
}
Try this code:
et.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) {
et.removeTextChangedListener(this);
try {
String givenstring = s.toString();
Long longval;
if (givenstring.contains(",")) {
givenstring = givenstring.replaceAll(",", "");
}
longval = Long.parseLong(givenstring);
DecimalFormat formatter = new DecimalFormat("#,###,###");
String formattedString = formatter.format(longval);
et.setText(formattedString);
et.setSelection(et.getText().length());
// to place the cursor at the end of text
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
et.addTextChangedListener(this);
}
});
I use a TextWatcher to trig on every change in EditText, and use this code to separate currency sections and then set to EditText after every character changes:
public static String formatCurrencyDigit(long amount) {
return String.format("%,d%s %s", amount, "", "");
}

Changing TextInputLayout's Hint value as the user types in it

Here is my TextInputEditText inside TextInputLayout. The hint you can see is set on TextInputLayout.
The user must write 255 characters otherwise the post is not valid.
I want the digit 255 to decrease as the user types and when reached to 0, the hint should be blank.
Here is my code :
private int charactersLeft = 256; is declared outside onCreate method.
And this code is inside onCreate method :
final TextInputLayout postTextInputBase = findViewById(R.id.post_text_input_base);
final TextInputEditText postTextInput = findViewById(R.id.post_text_input);
postTextInput.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) {
if (charactersLeft == 0) {
postTextInputBase.setHint(null);
} else {
postTextInputBase.setHint((charactersLeft - 1) + " characters left");
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
I also tried to set charactersLeft to characterLeft -= 1 but, the java won't allow me to do that.
Then, how do I do this ?
Use app:counterEnabled="true"
Whether the character counter functionality is enabled or not in this layout.
Also use app:counterMaxLength="250"
Sets the max length to display at the character counter.
Try this
<android.support.design.widget.TextInputLayout
android:id="#+id/post_text_input_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:counterEnabled="true"
app:counterMaxLength="250">
<EditText
android:id="#+id/post_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="UserName" />
</android.support.design.widget.TextInputLayout>
OUTPUT
EDIT
public class RecyclerViewActivity extends AppCompatActivity {
TextInputLayout postTextInputBase;
EditText postTextInputEditText;
int textLength = 9;
int len = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_view);
postTextInputBase = findViewById(R.id.post_text_input_base);
postTextInputEditText = findViewById(R.id.post_text_input);
postTextInputBase.setHint(textLength + " characters left");
postTextInputEditText.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) {
// first check your EditText is empty or not
if (!TextUtils.isEmpty(postTextInputEditText.getText().toString())) {
int len = postTextInputEditText.getText().toString().length();
// than check that editText text length is less than max length or not
// for test case i have set max length 10
if (len < 9) {
// if length of text is less than max length than use minus one from max length and set error in your text input layout
textLength--;
} else {
textLength++;
}
postTextInputBase.setHint(textLength + " characters left");
} else {
textLength = 9;
}
}
#Override
public void afterTextChanged(Editable s) {
if(postTextInputEditText.getText().toString().isEmpty()){
textLength = 9;
postTextInputBase.setHint(textLength + " characters left");
}
}
});
}
}
OUTPUT
EDIT 2 If you need set hint than use this
postTextInputBase.setHint(textLength + " characters left");
OUTPUT
NOTE Don't forgot to set android:maxLength="10" in edittext
Try this. Works with your existing code.
int charactersLeft = 256;
final TextInputLayout postTextInputBase = findViewById(R.id.post_text_input_base);
final TextInputEditText postTextInput = findViewById(R.id.post_text_input);
postTextInput.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) {
if (s.length() == 0) {
postTextInputBase.setHint(null);
}else {
postTextInputBase.setHint((charactersLeft - s.length()) + " characters left");
}
}
});
and Add android:maxLength="256" to your TextInputEditText
You may do it programatically using setOnKeyListener on the edit text.
TextInputLayout postTextInputBase = findViewById(R.id.post_text_input_base);
TextInputEditText postTextInput = findViewById(R.id.post_text_input);
postTextInput.setOnKeyListener((v, keyCode, event) -> {
// Do other things needed
postTextInputBase.setHint("Characters left: " + (256 - postTextInput.getText().length()));
return false;
});
To change Hint text only you can just change it on focus change.
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus)
editText.setHint("Enter name");
else
editText.setHint("Name");
}
});

Deleting a nonnumerial character from a numerical editText

I am using this code to add a dash('-') in a phone number after the 3rd and 4th number. The code is working just fine. My problem is that when I press backspace, I can't remove the dash. I can even add dots and I can delete them if I press backspace, but with dash it's just impossible.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
MainActivity.headerName.setText("Verification");
phoneNumber = (EditText) getActivity().findViewById(R.id.phoneEditText);
int grup = 1;
phoneNumber.addTextChangedListener(new TextWatcher() {
int keyDel;
String a= phoneNumber.getText().toString();
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
phoneNumber.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KEYCODE_DEL) {
a = a.replace("-" , "");
phoneNumber.setText(a);
keyDel = 1;
}
return false;
}
});
if (keyDel == 0) {
int len = phoneNumber.getText().length();
if(len == 3 || len == 7) {
phoneNumber.setText(phoneNumber.getText() + "-");
phoneNumber.setSelection(phoneNumber.getText().length());
}
} else {
if(KeyEvent.isModifierKey(KEYCODE_DEL)) {
a = a.replace("-" , "");
phoneNumber.getText().toString().replace("-" , "");
phoneNumber.setText(a);
}
keyDel = 0;
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
I'm guessing that your UI widget is formatting its text. So, after you remove the hyphen, the widget is putting it back.
I suggest you leave the widget alone. Instead, when you need to use the phone number, remove the formatting characters from the value.
String.replaceAll("[^\\d]", "")
You would use this code when retrieving the value from the widget for some external use. So, you might have a method
public String getPhoneNumberUnformatted() {...}
That returns only the digits of the widget's value.

Using TextChanged listener on two relative text fields

This is my first question. I have very basic java training and I am developing a simple app in Android Studio right now. The app is a temperature converter that reads one TextField and after applying a method, it shows output in the other TextField in Realtime.
So, here's what I'm doing:
A screenshot of ActivityMain.xml
The code:
public class MainActivity extends AppCompatActivity {
private EditText tc;
private EditText tf;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tc = (EditText) findViewById(R.id.TempInC);
tf = (EditText) findViewById(R.id.TempInF);
So far so good. tc gets the input from Temperature in Celsius TextField, and tf gets input from Temperature in Fahrenheit TextField.
After that, I have:
tc.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 strTempCval = null;
strTempCval = tc.getText().toString();
if (strTempCval.isEmpty()) {
tf.setText(null);
} else {
double tempCval = Double.parseDouble(strTempCval);
double ctofVal = toF(tempCval);
String fResult = String.valueOf(ctofVal);
tf.setText(fResult);
}
}
});
This part takes the tc input, and converts it to fahrenheit by using toF method (in the MainActivity class, at the end), and show it in the tf TextField.
The next thing I want to do is the exact reverse of the above code, with the tf input, so here it goes:
tf.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 strTempFval = tf.getText().toString();
if (strTempFval.isEmpty()) {
tc.setText(null);} else {
double tempFval = Double.parseDouble(strTempFval);
double ftocval = toC(tempFval);
String resultC = String.valueOf(ftocval);
tc.setText(resultC);
}
}
});
}
Now the problem is
...that if I'm using one of the above (either the one that converts c to f, or the one that converts f to c.), it works just fine (For example, if I comment out/disable one of these blocks). However, if I try to use both of the above functions simultaneously at the same time, the application crashes. Obviously because both TextChangedListeners are trying to manipulate/interact with each other.
Although, if required, the next part of the code is here: (The methods)
public double toC (double fVal){
double cResult;
cResult=(fVal-32)*5/9;
return cResult;
}
public double toF (double cVal){
double fResult = (cVal*9/5)+32;
return fResult;
}
//MainActivity ends here.
Whew, so that's all the source code there. I hope someone can help me because I am very frustrated at this as I can't use OnKeyListener (intended for hard input). Any help would be highly appreciated as I have been stuck at it for days! A bundle of thanks in advance for anyone who is willing to help me!
you will be getting a stackOverflowException which is because it goes into infinite loop
so use hasFocus() like this to solve your problem, as only the EditText beings edited by the user will have focus. do this for both EditTexts
tf.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) {
if(tf.hasFocus()) {
String strTempFval = tf.getText().toString();
if (strTempFval.isEmpty()) {
tc.setText(null);
} else {
double tempFval = Double.parseDouble(strTempFval);
double ftocval = toC(tempFval);
String resultC = String.valueOf(ftocval);
tc.setText(resultC);
}
}
}
});
}

Categories

Resources