I have a text field where the start symbol is $ (could be euro or pound depending on an application setting). I need to make it so that if the user clicks before the symbol nothing will happen. In other words, the selection must remain after the symbol. I tried doing something like this but it seems wrong and it gave me an error:
billAmount.addTextChangedListener(new TextWatcher() {
//other methods
#Override
public void afterTextChanged(Editable s) {
billAmount.setText(currencySymbol + billAmount.getText().toString());
}
});
I was thinking of using an inputFilter but nothing I tried worked. I'm also not allowed to use a TextView right before the EditText.
First, in your code sample, the reason you are getting an error is because, as others have said, you are calling the setText method inside the afterTextChanged method. Calling setText is obviously changing the text which causes afterTextChanged to be called again. This results in the afterTextChanged being called continuously until there is eventually a stack overflow.
You have two issues: 1) You want to always keep the cursor positioned after the currency symbol, and 2) You want to make sure the currency symbol is never somehow removed.
The easiest way to solve #1 is to create a subclass of EditText and override the onSelectionChanged method.
public class MyEditText extends EditText {
// ...
#Override
public void onSelectionChanged(int selStart, int selEnd) {
super.onSelectionChanged(selStart, selEnd);
// Make sure the text's length is greater than zero.
// Then, if the cursor is at position zero...
if (getText().length() > 0 && selStart == 0) {
// ...move it over to position one.
setSelection(1, selEnd);
}
}
}
This will force the cursor to always go after the currency symbol even if the user attempts to move it before it. The check getText().length() > 0 is to ensure that the EditText contains at least one character, otherwise attempting to move the cursor will result in an Exception.
As for #2, there are a couple ways to go at it. You can attempt to use some instance variables inside your TextWatcher to keep track of when the text needs to be formatted, but that won't prevent the unnecessary method calls from actually happening, and it adds some unneeded complexity. I think it would be easier to simply use an InputFilter, which you can specify in your extended EditText's constructor.
public class MyEditText extends EditText {
public MyEditText(Context context) {
super(context);
// Set the EditText's input filter.
setFilters(new InputFilter[] { new InputFilter {
#Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
// If the currency symbol is about to be replaced...
if (dstart == 0)
// Add the currency symbol to the front of the source.
return currencySymbol + source;
// else
// Return null to indicate that the change is okay.
return null;
}
}});
}
// ...
}
In the filter method, the dest parameter represents the EditText's text, and the dstart and dend parameters represent the start and end positions of the portion of the text that is about to be replaced. Since the currency symbol should always be the first character, we know it is about to be replaced if dstart is zero, in which case we simply return the source (which represents the replacement text) with the currency symbol placed in front. Otherwise, we indicate that the change is okay by returning null.
I tested it, and it seems to work for what you need.
On a side note, although I understand that you're not "allowed" to use a TextView, I think it's worth reiterating that using one would provide a much better solution to this problem. One particularly useful solution being to have a hidden EditText contain the raw input from the user, and having the TextView on top of the EditText. You would use a TextWatcher to update the TextView with the properly formatted input from the EditText.
I guess you are getting StackOverFlowException.
try this
String oldValue="";//instace variable
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//bilamount always starts with your currency symbol
if (s != null && s.length() == 0) {
editText.setText("$");
editText.setSelection(1);
}
if (s != null && s.length() > 0) {
String billAmount = s.toString();
if (!oldValue.equals(billAmount)) {//minimize unnecessary setText() method call
oldValue= billAmount;
editText.setText(billAmount);
editText.setSelection(billAmount.length());
}
}
}
Note : your EditText first init with your currencySymbol i.e. billAmount.setText(currencySymbol);
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'm creating an application which updates users on the score of a football match either in real time or as a final result. At least one score must be inputted in order for the TextView to be updated and the relevant score to be displayed. I'm checking that at least 1 of a pair of EditText fields is not empty using the following code:
if(!(et_current.getText().toString().isEmpty())||(!(et_final.getText().toString().isEmpty()))
&& (!(et_current2.getText().toString().isEmpty())||(!(et_final2.getText().toString().isEmpty()))){
if(!(et_final.getText().toString().isEmpty()))
tv_final.setText(et_final.getText().toString());
else
tv_current.setText(et_current.getText().toString());
if(!(et_final2.getText().toString().isEmpty()))
tv_final2.setText(et_final2.getText().toString());
else
tv_current2.setText(et_current2.getText().toString());
}
I want to be able to set the correct TextView so I have another if statement inside the original if statement to see ensure the correct score is being updated.
When I run the code, I do not seem to be getting past the first if statement. Am I using the correct format or is there an better way to complete these checks?
Thanks!
For readabilities sake, get some variables going
boolean currentEmpty = et_current.getText().toString().isEmpty();
boolean current2Empty = et_current2.getText().toString().isEmpty();
boolean finalEmpty = et_final.getText().toString().isEmpty();
boolean final2Empty = et_final2.getText().toString().isEmpty();
And then your code can be much cleaner. Something like
if( (!currentEmpty || !finalEmpty) || (!current2Empty || !final2Empty)) {
if(finalEmpty) {
tv_current.setText(et_current.getText());
}
else {
tv_final.setText(et_final.getText());
}
if(final2Empty) {
tv_current2.setText(et_current2.getText());
}
else {
tv_final2.setText(et_final2.getText());
}
}
I'm not sure if that is completely correct as the requirement is not entirely clear to me, but it should atleast be a good start to follow what's going on.
I am currently making a text adventure game in Java, but I have come across a problem:
I need the value of a String variable to change each time the value of a particular int variable changes.
I want the program to perform this task (then continue where it left off) each time the value of an int variable changes:
if (enemyposition == 1) {
enemyp = "in front of you";
}
else if (enemyposition == 2) {
enemyp = "behind you";
}
else if (enemyposition == 3) {
enemyp = "to your left";
}
else if (enemyposition == 4) {
enemyp = "to your right";
}
else {
enemyp = "WOAH";
}
Thanks! :D
You could make the code much shorter using an array.
String[] message = {"WOAH", // 0
"in front of you", // 1
"behind you", // 2
"to your left", // 3
"to your right"}; // 4
enemyp = (enemyposition > 0 && enemyposition < 5) ? message[enemyposition] :
message[0];
The question you're asking sounds like it might be answerable by creating a class to hold the enemyposition integer. Add a "setter" method to your class to set the integer. You can write your setter method so that when the integer is set, it also sets up a string. Then write a "getter" method to retrieve the string. That's one common way of making sure two variables change together.
public class EnemyPosition {
private int enemyposition;
private String enemyp;
public void setPosition(int n) {
enemyposition = n;
enemyp = [adapt your code to set this based on the position]
}
public String getEnemyp() {
return enemyp;
}
}
I'm sure there are a lot of details missing, but you get the idea. Then instead of int enemyposition in the rest of your code, use EnemyPosition enemyposition = new EnemyPosition(), and use the setPosition method instead of assigning to it.
That's not the only solution (an array or Map that maps integers to strings may be good enough), but it's one OOP way to do things.
I'm trying to implement iPhone like PIN-code authorization with 4 EditText blocks like this:
I'm using TextWatcher to check if field was changed so I can jump between blocks.
Here is the code:
#Override
public void afterTextChanged(Editable s) {
if (del && index > 0) {
pin[index - 1].requestFocus();
}
else if ( ! del && ind < 3) {
pin[index + 1].requestFocus();
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
del = count != 0;
}
Everything works fine except when block is empty and DEL/BACKSPACE is pressed, I want to go back to previous block and clear its' value.
This is where TextWatcher fails me since no change was made in empty block it doesn't do anything.
I have tried using keyEventListener but it only catches events on emulator not on actual device via virtual keyboard.
Can anyone suggest an idea of how can I catch DEL event or any other way to implement this?
Maybe you can check if the field is empty before and after change? Don't know if any other key press can leave the field empty and so you can say, back was pressed and jump to previous field. Ok this is not a real technical solution, but just a different way of viewing the problem.
I found a workaround for this issue. This is probably not the best solution, but it works for me.
Aside from TextWatcher I've added InputFilter to blocks
#Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
if ( end == 0 && ind > 0 && dest.length() == 0 ) {
pin[ind - 1].requestFocus();
}
return null;
}
I also think it's a better idea to port the rest of the code from TextWatcher to InputFilter
I am building a GWT component to behave much like the comments box here on stackoverflow, and other sites. I am trying to register listeners for KeyPress, Change and ONPASTE events that will update my status line with number of characters remaining, etc.
It works except it is always one character behind the actual number of characters in the text area. I set the max number of characters to 10. When I type the first character it still says, "10 characters remaining". It doesn't update the status line until I type the second character and then it is one off, it says 9 characters remaining when the second character is typed.
When I BACKSPACE or DELETE, it is also one off, when there are no characters it still says "9 characters remaining" until I press the BACKSPACE or DELETE a second time.
I am getting this behavior in both Firefox, Chrome and Internet Explorer on Windows. So I think I am not registering something correctly.
I know this has something to do with when the events are getting fired, but I have spend hours on trying to diagnose this behavior and have run out of ideas.
Here is where I am registering the event handlers, the complete code is BoundedTextAreaWithFeedback.
private void registerHandlers()
{
final BoundedTextAreaWithFeedback outer = this;
this.textArea.addChangeHandler(new ChangeHandler()
{
public void onChange(final ChangeEvent changeEvent)
{
outer.validate();
}
});
this.textArea.addKeyPressHandler(new KeyPressHandler()
{
public void onKeyPress(final KeyPressEvent keyPressEvent)
{
outer.validate();
}
});
this.panel.addFocusHandler(new FocusHandler()
{
public void onFocus(final FocusEvent focusEvent)
{
outer.textArea.setFocus(true);
}
});
// capture paste events
this.textArea.sinkEvents(Event.ONPASTE);
}
Here is the validate() method.
private boolean validate()
{
final boolean isValid;
final int len = this.textArea.getText().length();
if (len < this.minLength)
{
this.status.setText("Enter at least " + this.minLength + " characters.");
this.status.setStyleName("input-status-underflow");
isValid = false;
}
else if (len > this.maxLength)
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-overflow");
isValid = false;
}
else
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-ok");
isValid = true;
}
return isValid;
}
I just started adding every addXXXHandler() until one worked.
this.textArea.addKeyUpHandler(new KeyUpHandler()
{
public void onKeyUp(final KeyUpEvent event)
{
outer.validate();
}
});
Seems to have done the trick.
Here is the working code, CTRL-V and paste from context menu also work now.
Try using a DeferredCommand to execute the validation code. I believe the problem is that when the event is firing, they character is not yet added to the text area. The DeferredCommand will not execute until any pending event handlers have finished, allowing the length of the text to be calculated correctly.
See this question for an example of using a DeferredCommand.