I have an EditText (accepts 0-9) with a listener. I want to grab input as it's entered, apply a calculation, and display it in the same EditText box.
The box initially displays $0.00. When the user inputs a 2, I want to grab that from the box, parse it to remove the $ and decimal, convert it to an int... divide it by 100 and put a $ in front of it. After setText, it should display $0.02. If they then press 5, I'll grab it, parse it, end up with 25, do the math and it should display $0.25, etc.
I don't know if this is the best way, I'm open to new ideas. Here is my current code:
mEditPrice.addTextChangedListener(new TextWatcher(){
DecimalFormat dec = new DecimalFormat("0.00");
#Override
public void afterTextChanged(Editable arg0) {
}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
String userInput = mEditPrice.getText().toString().replaceAll("[^\\d]", "");
int userInputInt = Integer.parseInt(userInput);
mEditPrice.setText("$"+dec.format(userInputInt / 100));
}
There's a few issues to deal with here before you can achieve the kind of functionality you desire.
Whenever you deal with a TextWatcher you need to be careful when setting the text of the EditText object being watched. The reason for this is that every time you call setText on it, it will trigger the watcher again, causing your code to go into an infinite loop.
To prevent this, you should set the value of text you want to set into a variable outside of the onTextChanged method. When entering the method, check against this variable and only perform your processing code if the value is different from the CharSequence.
The integer variable userInputInt, when divided by 100, will be equal to zero.
This should be changed to a double to produce values like 0.02 etc.
After those changes we can get the EditText to show $0.02 after entering a 2. But because we have set the value of the EditText in code, the next entry into the EditText will be added to the beginning of the text. Then if we enter a '5' we get $50.02.
To overcome this, the last thing we need to do is set the position of the EditText to the end of the string, using the set position method.
Here's the final solution:
private String value;
mEditPrice.addTextChangedListener(new TextWatcher(){
DecimalFormat dec = new DecimalFormat("0.00");
#Override
public void afterTextChanged(Editable arg0) {
}
#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.toString().equals(value)){
String userInput = mEditPrice.getText().toString().replaceAll("[^\\d]", "");
double userInputDouble = Double.parseDouble(userInput);
value = ("$"+dec.format(userInputDouble / 100));
mEditPrice.setText(value);
mEditPrice.setSelection(value.length());
}
}
});
Related
I have an editText box and when user writes "hello" I want only change "hello" font-family change to italic but others text font-family stay same only change "hello"
String detectText, text;
detectText = "hello";
text = title.getText().toString();
detectText.
Could you please help me?
As someone said, you need a text watcher to be able to make changes when the text is changed. You also need spans to be able to style parts of the text. Here's a way to do it:
editText.addTextChangedListener(new TextWatcher() {
private static final String KEYWORD = "hello";
#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) {
// Remove previous spans.
for (StyleSpan span : s.getSpans(0, s.length(), StyleSpan.class)) {
s.removeSpan(span);
}
// Add new spans for every occurrence of the keyword.
int i = 0;
while (i != -1) {
i = text.toString().indexOf(KEYWORD, i);
if (i != -1) {
s.setSpan(new StyleSpan(Typeface.ITALIC), i, i + KEYWORD.length(),
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
i += KEYWORD.length();
}
}
}
});
The text watcher has three methods called at different times of the editing, but it's only safe to make changes to the text in afterTextChanged. There, all previous style spans are removed then the text is scanned to add new ones.
Note that performance might be a problem if you intend to turn this into something a lot more complex, like a syntax highlighter. Right now all spans get readded everytime the user changes a single character.
I searched different questions but found nothing specific about my problem. I am changing text color by selecting color and works successfully however when I start deleting my edit text after typing a color text I get this error.
myedittext.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) {
spannableString.setSpan(new ForegroundColorSpan(Color.parseColor(txtColor)), start, start+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
I get the following error
java.lang.IndexOutOfBoundsException: setSpan (118 ... 119) ends beyond length 118
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1309)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:680)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:672)
at com.apps.primalnotes.Fragments.EditorFragment$16.onTextChanged(EditorFragment.java:842)
at android.widget.TextView.sendOnTextChanged(TextView.java:10611)
at android.widget.TextView.handleTextChanged(TextView.java:10715)
at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:14057)
I am writing in two colors now like this
now when i save it. it saves in pink color only and shows me like this
but now when i save it again without any changes it save in the colors i wrote it
The onTextChanged method is invoked to tell you that within CharSequence s, number of character count beginning at start have just replaced old text that had length before.
What is happening is that when user presses backspace, start is at the upper limit of your charsequence i.e. If you had seven character before, start is 6 which is the same as the last element. You are doing start+1 which is always a number out of index range.
myedittext.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(start < s.length() - 1 || count > before){
spannableString.setSpan(new ForegroundColorSpan(Color.parseColor(txtColor)), start, start+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
Didn't get to try that code but it should work. It's just to show you an idea of what you are doing wrong and what you should be doing.
When you delete text from the end of the string, the onTextChanged() method will be invoked with values representing the fact that the string is now shorter. It looks like you've written your code to always assume that the length will be longer; you're coloring in the just-typed character. But if you delete a character instead, you probably don't want to do this.
You could add a check to make sure that count is greater than before, this at the very least will indicate that text was added to the string.
if (count > before) {
spannableString.setSpan(...);
}
I'm making an Android calculator and I get 9.223372E+18 when I divide by zero. why wouldn't it show NaN or crash? I think that it results in 9.223372E+18 because that's the largest possible double value, since I'm dividing by zero and using a double data type. Since it will confuse the user, how do I get around this?
Respond to Comments
Hi guys, thanks for all your responses. I appreciate it. I posted my code below.
public class CFM extends ActionBarActivity {
Double cfm, ac, volume;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cfm);
EditText e1 = (EditText) findViewById(R.id.editText1);
EditText e2 = (EditText) findViewById(R.id.editText2);
TextView t1 = (TextView) findViewById(R.id.editText3);
t1.setEnabled(false);
t1.setFocusable(false);
e1.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
EditText e1 = (EditText)findViewById(R.id.editText1);
EditText e2 = (EditText)findViewById(R.id.editText2);
volume = Double.parseDouble(e1.getText().toString());
cfm = Double.parseDouble(e2.getText().toString());
TextView t1 = (TextView) findViewById(R.id.editText3);
ac = cfm * 60 / volume;
t1.setText(Double.toString((double) Math.round(ac * 100) / 100));
}
});
e2.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
EditText e1 = (EditText)findViewById(R.id.editText1);
EditText e2 = (EditText)findViewById(R.id.editText2);
volume = Double.parseDouble(e1.getText().toString());
cfm = Double.parseDouble(e2.getText().toString());
TextView t1 = (TextView) findViewById(R.id.editText3);
ac = cfm * 60 / volume;
t1.setText(Double.toString((double) Math.round(ac * 100) / 100));
}
});
}
9223372036854775807 (roughly 9.223372E+18) is the largest possible long value. The only way I can see this coming from dividing by zero is if you have a variable of type long. For example, the following code prints 9223372036854775807.
long a = 1;
a /= 0.0;
System.out.println(a);
When you divide a long by a double, the long is converted to a double first and the result is a double. Any positive double divided by 0.0 gives Double.POSITIVE_INFINITY, so 1/0.0 is Double.POSITIVE_INFINITY. Since a has type long, this is converted back to a long, giving the largest possible long value.
However, we would need to see your code to understand why you have variables of type long.
Edit
Having seen your code, I now realise that the problem is not a variable of type long but your use of Math.round. This is defined as follows:
Returns the closest long to the argument, with ties rounding up.
Math.round therefore rounds Double.PositiveInfinity down to 9223372036854775807. A better approach to displaying the result to 2 decimal places would be something like this.
String result = Double.isInfinite(ac) || Double.isNaN(ac) ? "Error"
: new BigDecimal(ac).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
t1.setText(result);
This will print "Error" if the user tries to divide by zero.
When calculating your value, use a detection mechanism to look for that number and show an error of 'cannot divide by zero'.
Either that or see if there is an exception handler that handles division by zero. Check here for an example of what exception to throw:
How should I throw a divide by zero exception in Java without actually dividing by zero?
or here: Java division by zero doesnt throw an ArithmeticException - why?
OR as deyur mentioned, yes you can always check if one of the arguments is zero and handle it that way.
If you are still having issues beyond this, share the core code snippets so we can help.
This question already has an answer here:
EditText Minimum Length & Launch New Activity
(1 answer)
Closed 8 years ago.
I am a new developer on Android and Java. How can I make at least 10 characters in EditText ? Also, when the user enter a value less than 10, the application send an error message on screen. How can I do these ? [ edittext > = 10 ]
Use something like this:
EditText et = (EditText) findViewById(YOUR_EDITTEXT);
String s = et.getText().toString();
if(s.length() <= 10){
et.setError("Must exceed 10 characters!");
} else {
// ...
}
You can do that in several ways, but you can try this way:
if (myEditText.getText().length() < minLength) {
//Your message to there is no enough caracters
} else {
//Your action if it is satisfied.
}
You can set minLenght to 10, or whatever, or simply ask if value is less than 10.
I hope that you get idea from this.
You can use text watcher to check the user input and decide what to do inside
EditText editText = new EditText(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) {
}
});
Yo can validate your TextView and if it doesn't fit your requirements, use myTextView.setError(String) to show an error.
If not you will have to implement myTextView.addTextChangedListener(...) and do things manually.
Hope it helps.
I've got a bit of a concept question I'd like to have answered.
I'm aiming to make an android application in which textboxes can only have specific types of inputs. As an example, decimal numbers are easy, you use a Number text box. However, if I were to use hexidecimal numbering system as an example, how can I have my box reject any input that is attempted to be entered that is not a valid hexidecimal character (0-F)? This concept could be extended to the octal and binary numbering systems. Ideally, the keyboard which appears when the box is clicked would only display valid characters for that particular box, but I'm not sure if that is possible.
Thanks!
K.
Overwrite the textbox listener and on key stroke, get the inputed text, run the conditions you want. If it passes, it is acceptable, if not you warn the user ..
EXAMPLE of listener:
tv = (TextView)findViewById(R.id.charCounts);
textMessage = (EditText)findViewById(R.id.textMessage);
textMessage.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){
//Check if text is hexadecimal
}
});
Look into using a filter
http://developer.android.com/reference/android/widget/Filter.html