im writing a simple app where you can input data to database through app. I have to make conditions for example: you can't put digits in Name field. I know I have to do this in onClick, but I dont really know how. Can you help me?
public void onClick(View v)
{
switch (v.getId()){
case R.id.insertButton:
dm.insert(editName.getText().toString(),
editAge.getText().toString(),
editSurname.getText().toString(),
editSex.getText().toString(),
editPesel.getText().toString());
break;
case R.id.selectAllButton:
showData(dm.selectAll());
break;
case R.id.searchButton:
showData(dm.searchName(editSearch.getText().toString()));
break;
case R.id.deleteButton:
dm.delete(editDelete.getText().toString());
break;
}
}
You can cast the input to String in a try/catch, or set the input type to integer (use android:inputType="number" in your xml)
I know I have to do this in onClick.
onClick is perhaps not the ideal place as the user has already input the data and is therefore after the fact, as such.
Frequently it would be better to not allow unacceptable(sic) input when the user tries to enter such input.
There are alternatives, perhaps the simplest is to restrict the characters that can be input via the XML definition of the EditText e.g. to restrict to letters only then you could use :-
android:digits="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
To allows spaces you could use (space added between lower and upper case) :-
android:digits="abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ";
However, really you should use a String Resource so you could easily cope with multiple languages (locales).
Therefore you could create a String resource (res/values/strings.xml) such as :-
<string name="alphabet">"abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
and then use :-
android:digits="#string/alphabet"
Programatically (alternatively) you could use an InputFilter :-
mAlphaBet = getResources().getString(R.string.alphabet);
// Define the Input Filter
InputFilter inputfilter = new InputFilter() {
public CharSequence filter(CharSequence s,
int start,
int end,
Spanned dest,
int deststart,
int destend) {
for (int i=0; i < end; i++) {
// If not in the alphabet then suppress input
if(!mAlphaBet.contains(String.valueOf(s.charAt(i)))) {
return "";
}
}
// Indicate input is OK
return null;
}
};
// Apply filters (just the 1) to the EditText
editName.setFilters(new InputFilter[]{inputfilter});
mAplhaBet is retrieved from the resources as above, again catering for locales if defined.
Related
First I have to say I have read similar questions and answers here on SO and this question is basically a duplicate of this question and many others but the answers given to those questions doesn't work like the way i want it.
The problem:
Setting length filter on my EditText programmatically like this:
editText.setFilters(new InputFilter[]{new LengthFilter(10)} );
The only thing it does is hide the text that go over the limit in the EditText. It still shows the long (unlimited) text in suggestion box and i have to delete (backspace) for each letter that go over before being able to delete what is shown in the EditText.
Suggested Solutions:
Setting InputType to textFilter.
Programmatically I did this:
editText.setInputType( InputType.TYPE_TEXT_VARIATION_FILTER );
It hides suggestions but the unlimited text is still present and i still have to use backspace to delete letters that shouldn't be present.
Setting InputType to textNoSuggestions|textVisiblePassword.
Programmatically I did this (had to add TYPE_CLASS_TEXT too otherwise it wouldn't work):
editText.setInputType( InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD );
This one does work but the problem is it stops "gesture typing" and it changes the font to monospace.
Better Solutions?
As you can see these two methods don't actually work without additional problems. Is there any other way of doing this that I missed. Should I just use a TextWatcher if I want to keep gesture typing and suggestions?
I ended up using a TextWatcher instead. I'm not sure if it is the best way to do this but it does work with suggestions and it doesn't turn off gesture typing or change the font style. Here's how I did it (I'm quite new to android so if this needs improvement feel free to let me know).
I added an example in the comments to clarify what is going on.
Make these global variables:
private boolean mWatcherIsBlocked = false;
private String mBeforeChange;
private String mFilteredString;
private int mCursorPosition = 0;
Then create the TextWatcher and add it to your EditText
final int maxLength = 10; // desired length limit
/**
* lets say our EditText is showing "abcdefgh". We select "cdef" from it and
* paste a new text "ijklmnop" in the middle. What we should get according to
* our maxLength is this:
* (1) "ab" (0th up to the letter from before_change_text we were selecting) +
* (2) "ijklmn" (part of the text we pasted minus the number of letters the whole
* after_change_text goes over the 10 letter limit) +
* (3) "gh" (last part of before_change_text that wasn't selected)
*
* so the new text has to be "abijkmngh"
*/
TextWatcher textWatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// get before_change_text if textWatcher isn't blocked
if (!mWatcherIsBlocked) mBeforeChange = s.toString();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!mWatcherIsBlocked){
// get after_change_text if textWatcher isn't blocked
String after = s.toString();
// if after_change_text's length is bigger than the limit
if (after.length() > maxLength) {
// see how much it goes over the limit
int over = after.length() - maxLength;
// add parts (1) and (2) like our example above
String st = mBeforeChange.substring(0, start) + // (1)
after.substring(start, start + count - over); // (2)
// get where the cursor position should be after pasting (
// = after the last letter we could paste = length of (1) + (2) )
mCursorPosition = st.length();
// now add part (3) of our text to the first two
st += mBeforeChange.substring(
mBeforeChange.length() - (maxLength - st.length()),
mBeforeChange.length());
// now assign this new text to a global variable
mFilteredString = st;
} else {
// if after_change_text hasn't gone over the limit assign it
// directly to our global variable
mFilteredString = s.toString();
}
}
}
#Override
public void afterTextChanged(Editable s) {
// if filtered text is not the same as unfiltered text
// or textWatcher is not blocked
if (!mFilteredString.equals(s.toString()) && !mWatcherIsBlocked) {
// block textWatcher to avoid infinite loops created by setText
// (this might not work as I well as I think!)
mWatcherIsBlocked = true;
// set new text to our EditText
editText.setText(mFilteredString);
// set its cursor position
editText.setSelection(mCursorPosition);
// unblock the textWatcher
mWatcherIsBlocked = false;
}
}
};
// add the TextWatcher to our EditText
editText.addTextChangedListener(textWatcher);
I have an EditText in which i want to allow only alphabets and numbers of any language. I tried with different android:inputType and android:digits in XML.
I tried with set TextWatcher to edittext in which onTextChanged() is like
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
switch (et.getId()) {
case R.id.edtMultiLang: {
et.removeTextChangedListener(watcher2);
et.setText(s.toString().replaceAll("[^[:alpha:]0-9 ]", ""));
// et.setText(s.toString().replaceAll("[^A-Za-z0-9 ]", ""));
et.addTextChangedListener(watcher2);
break;
}
}
}
This is working fine. But whenever i tried to clear text, cursor is moving to start for every letter. Means when i clear a single letter, cursor moving to start.
If i use like android:digits="abcdefghijklmnopqrstuvwxyz1234567890 ", it allows me to type only alphabets and numbers of english. It is not allowing me to enter any other language text As i given only English related alphabets here. But my requirement is to allow copy/paste of other language's alphabets and letters also.
I hope we can do this by using Patterns, TextWatcher and InputFilter. But i didn't find better way.
Please let me know if there any way to do this.
The option you mention to resolve the problem is easy and fast, if you use a filter your code will be like this:
public static InputFilter filter = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String blockCharacterSet = "~#^|$%*!#/()-'\":;,?{}=!$^';,?×÷<>{}€£¥₩%~`¤♡♥_|《》¡¿°•○●□■◇◆♧♣▲▼▶◀↑↓←→☆★▪:-);-):-D:-(:'(:O 1234567890";
if (source != null && blockCharacterSet.contains(("" + source))) {
return "";
}
return null;
}
};
editText.setFilters(new InputFilter[] { filter });
i create a form with an EditText that takes in input numberDecimal (i set android:inputType="numberDecimal" in related XML file) and i write the following activity that prevent inserting numbers with more than 2 decimal places (i used .setFilters()). In addition i set a suffix in the same EditText and i would avoid that users can delete this suffix, neither add some input after it. I mean that if users go at the end of the EditText and tries to press backspace button the cursor goes at the begin of the suffix " m" (including space).
How to do that?
public class InputForm extends Activity {
EditText inputField;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.input_form);
inputField = (EditText) findViewById(R.id.editInput);
inputField.setText(" m");
inputField.setSelection(0);
inputField.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(2)});
}
public class DecimalDigitsInputFilter implements InputFilter {
Pattern mPattern;
public DecimalDigitsInputFilter(int digitsAfterZero) {
mPattern = Pattern.compile("[0-9]+((\\.[0-9]{0," + (digitsAfterZero-1) + "})?)||(\\.)?");
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
int input_length = dest.length() - 2; // lenght of the input without " m"
Matcher matcher = mPattern.matcher(dest.subSequence(0, input_length));
if(!matcher.matches())
return "";
return null;
}
}
}
One way that you can manage keeping the right side of your EditText would be to arrange the layout such that it is composed of 2 EditText views. One with a layout attribute to the right and another with a layout to the left of the suffix EditText filling up the remainder of the layout window.
Then make the second EditText unselectable. If you don't put borders around the EditText and force the text in the window on the left to type from right to left, then you will get the appearance you desire.
You could also keep track of the cursor and then after input you could change the position of the cursor if it is in the wrong location, or check the input for having the suffix that you are expecting and replace it as they type. This will have very little visually noticeable change. But I don't believe there is a built-in way to handle the approach you are requesting.
How to allow only a valid floating point number into a text field floating point like these only
2.353
-2.354
4444.45
Implement a focus listener on the field. When the focus changes from the textfield to any other part of your form simply use a regexp to check the validity of the input.
Something like :
^(-)?\d*(\.\d*)?$
Should do the trick.
Then use the pattern matching of Android to see if the input matches the regexp :
Pattern p = Pattern.compile("^(-)?\d*(\.\d*)?$");
Matcher m = p.matcher(inputString);
if (m.find()) {
////Found
}
else {
//Not found
}
But be aware of local settings...In France for example, the dot(.) used to separate the decimals is in fact a comma(,)
Use OnFocusChangeListener to achieve this.
//value pool
final String[] check = new String[]{"2.353","-2.354","4444.45"};
yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
String s = ((EditText)v).getText().toString().trim();
for(String tmp : check){
if(!TextUtils.isEmpty(s) && s.equals(tmp)){
//it ok
break;
}
else{
//do something
}
}
}
});
For edittext use android:inputType="number"
Convert the resulting string into an integer (e.g., Integer.parseInt(myEditText.getText().toString())`).
android:inputType="numberDecimal|numberSigned"
I have a situation where I would like the user to complete a sentence for me. For example, consider a EditText with a hint of "The last time I ". Normally, when a user clicks an EditText, the hint disappears, but I would like it to stay. Additionally, I would like the text to be permanent, so that it cannot be erased... leaving the user with only one option... complete the sentence.
The first part is fairly simple, just use the setText() method of EditText to place the hint. The difficult part is the latter. How can I have text in an EditText that the user cannot erase?
Well couldn't you do it in code? Some algorithim like, if the text is less than 16 characters (length of "The last time I ") then set the text to that. Therefore whenever they clicked it, if they tried to erase it, it would just go back to the default text.
Also, another idea..why don't you just make a TextView thats right edge aligns with the left edge of the EditText box, the user would never know that it was another box. This is acutally the best solution, if you don't want the text ever to be edited, just make it a TextView
Described problem can be solved using android.text.TextWatcher.
public class CompleteSentenceWathcher implements TextWatcher {
private final String initialText;
private int start;
private int after;
private int count;
public CompleteSentenceWathcher(String initialText) {
this.initialText = initialText;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
this.start = start;
this.count = count;
this.after = after;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if(start < initialText.length()) {
if(s.toString().startsWith(initialText)) {
return;
}
if(count >= 1 && after == 0) {
if(start+count+1 <= initialText.length()) {
s.replace(start, start+count, initialText.substring(start, start+count+1));
} else {
s.replace(start, start, initialText.substring(start, start+1));
}
} else if(count == 0 && after >= 1) {
s.delete(start, start+after);
}
}
}
}
Create an instance of EditText and add the TextWatcher.
EditText editText = new EditText(this);
editText.setText("I love");
editText.addTextChangedListener(new CompleteSentenceWathcher(editText.getText().toString()));
I've implemented this with an InputFilter, where _PERMANENT_HINT_TEXT is the text at the end of the EditText that I don't want the user to be able to modify. I recommend adding a color span to it, so that it is grayed out to hopefully look like a hint/disabled section of text. This should hopefully improve the UX as they should automatically assume it is unmodifiable, and not just wonder why some part of the EditText (that they usually can completely change) isn't "working". This approach allowed the text to be set after
the InputFilter was set on the EditText, which was a requirement for me since I used this on an EditTextPreference.
To be clear, I needed the permanent text to exist at the end of the EditText, instead of the beginning, but that should be symmetrical to my implementation.
new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int source_start, int source_end,
Spanned destination, int destination_start, int destination_end) {
final int protected_text_start = (TextUtils.isEmpty(destination)? source.length() : destination.length()) - _PERMANENT_HINT_TEXT.length();
// Allows input into unprotected region
if (source_start + destination_start - source_end < protected_text_start)
return null;
// Prevents deletion of protected region
else if (TextUtils.isEmpty(source))
return destination.subSequence(destination_start, destination_end);
// Ignores insertion into protected region
else
return "";
}
}
use EditText.setFilters(new InputFilters[] { /* InputFilter goes here */ }; to add it to the desired EditText.
Just checking for the length wouldn't be adequate... I could type "This is a really long text I put into the box" and it would accept it even though it doesn't begin with "The last time I" string.
Personally, I would probably go for the prevention method suggested of using a TextView over that of a check on the way out. But if you're going to validate it afterwards, you'd actually need to check the beginning of the returned string.