I have an editText that i want to control in length.
how can i avoid the user from entering a character which will lead the text to be longer than X ?
I have thought to use beforeTextChanged(CharSequence s, int start, int count,
int after) {
but then i'm not sure how to skip adding the character if i want.
The length is determined dynamically - getting this from the server side on activity start
Well, if you need to stop the user from entering a text longer than x, simply put android:maxLength="x" as an attribute for your EditText.
Or,
mEditText.setFilters( new InputFilter[]
{
new InputFilter.LengthFilter(<length>)
} );
use following property in edittext
android:maxLength="10"
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 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);
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
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 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());
}
}
});