I have a listview with an EditText in each row. The EditText is supposed to collect numeric values so I tried to keep the alpha keyboard off and allow the user to only see the numeric keypad.
What happens, though, is that when the listview is populated and I click on any EditText in the list, the numeric keyboard appears - but is then quickly replaced by the full qwerty keyboard - and the user must switch back to numeric to input numbers.
I've tried various combinations programmatically, like so:
mPercent.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL);
As well as multiple comnbinations of XML such as
android:inputType="phone"
or
android:digits="0123456789"
But, no matter the combination, they keyboard always rapidly switches back to qwerty and off the numeric keys.
I'm thinking it might be something with the TextWatcher. I use a textwatcher to indicate what has been typed. I remove it, add whatever text might be in that row's edittext and then add the textwatcher.
This is the guts of my custom adapter :
public View getView(final int position, View inView, ViewGroup parent) {
ViewHolder holder = null;
if (inView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inView = inflater.inflate(mLayoutResource, null);
holder = new ViewHolder();
holder.mPercent = (EditText) inView.findViewById(R.id.percent);
holder.mMaterial = (TextView) inView.findViewById(R.id.name);
inView.setTag(holder);
} else {
holder = (ViewHolder) inView.getTag();
}
mMaterial.moveToPosition(position);
holder.mPercent.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL);
// remove textwatcher on percentage
holder.mPercent.removeTextChangedListener(percentWatcher);
// insert the percentage for this row
final String material = mMaterial.getString(mMaterial.getColumnIndex(OptionsProvider.OPTIONS_DATA));
final EditText percent = holder.mPercent;
percent.setTag(material); // use material and position as keys into which of the many edittexts the textwatcher is watching
percent.setId(position);
holder.mMaterial.setText(material);
// persist any text the user may have typed in the comment box
if (percentages.containsKey(material)) {
percent.setText(percentages.get(material));
}
else {
percent.setText("");
}
// turn on textwatcher
percentWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// save this text and the position in which is resides.
// if the user scrolls before pressing send, only this position should
// contain the text
String text = percent.getText().toString().trim();
if (text.length() > 0) {
if ((position == percent.getId() &&
(material.equals( percent.getTag().toString())))) {
percentages.put(material, text);
Log.d(TAG, "Percentage inserted "+material+"="+text);
}
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
// force the EditText to stay with 3 digits (max of 100%)
#Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
int pct = Integer.parseInt(s.toString());
Log.d(TAG, " Material "+(String) percent.getTag()+ " = "+pct);
}
}
};
// add the textwatcher back to the edittext
holder.mPercent.addTextChangedListener(percentWatcher);
Anyone know if removing/adding a textwatcher corrupts the InputType? Is this a path I should explore to figure out why the keyboard always goes back to qwerty?
Might be that the ListView steals the focus. Try to add this your ListView
XML
android:descendantFocusability="afterDescendants"
Or in Java
listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
Related
I have an EditText which is supposed to have multi-line while typing and should have an action done when enter is pressed, meaning the soft keyboard should disappear and the cursor made invisible... basically the EditText should lose "focus".
Now this is done and working, but the problem is that the "enter" key leaves a new line in the EditText.
I have tried to remove it by setting the entire text to "", but the EditText is blank with a new line.
I have tried to remove it by replacing '\n' with a 's' and setting the text back, but the text starts in a new line.
String cap = caption.getText().toString().replace('\n', 's').trim();
caption.setText(cap);
Thanks in advance.
I know this is a late answer but maybe it can help someone.
I recently had this problem and I solved it by implementing an addTextChangedListener to my EditText.
Code:
EditText editText = new EditText(this);
layout.addView(editText);
editText.addTextChangedListener(new TextWatcher() {
boolean ignore = false; // This is used to prevent infinite recursion in the afterTextChanged method
#Override
public void afterTextChanged(Editable arg0) {
if (ignore) return;
ignore = true;
String s = arg0.toString();
if (s.length() > 0) {
// The condition checks if the last typed char's ASCII value is equal to 10, which is the new line decimal value
if (((int)(s.charAt(s.length()-1)) == 10)) {
String newStr = s.substring(0, s.length()-1); // Removes the new line character from the string
editText.setText(newStr);
editText.setSelection(editText.length()); // Sets the text cursor to the end of the text
}
}
ignore = false;
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
There might be better ways to get rid of the new line character, but this worked for me and seems simple enough.
I have 85 settings items that I need to display on a view. I cannot use a RecyclerView or a ListView because EditTexts are horrible. Doing the way I am doing causes a huge slow down. I do not want to make these manually. Any help is appreciated.
Relevant code:
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
LinearLayout ll = (LinearLayout) view.findViewById(R.id.ssm_ll);
List<Category> AllCats = (List<Category>) getArguments().getSerializable("Category");
temp = new LinearLayout(getActivity());
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
new Thread(new Runnable() {
public void run() {
for (Category cg : AllCats) {
LinearLayout tv = (LinearLayout) inflater.inflate(R.layout.scoring_setting_template, null);
TextView Catwording = (TextView) tv.findViewById(R.id.sst_catwording);
Catwording.setText("" + cg.getCatWording());
temp.addView(tv);
}
}
}).run();
temp.addView(temp);
ll.addView(temp);
}
Too Long for Comment, Not Sure if it Works, Just a Suggestion to Try
I haven't tested this at all, but it was too long to suggest trying in a comment. If it doesn't work let me know and I will delete this as a possible answer (please keep from your negative votes again I am not certain of this as an answer).
Since an Adapter in a ListView is supposed to handle creating the next view that isn't seen, which allows smooth scrolling, you could possibly still manage this in a ListView (theoretically). You could programmatically set the id and handle the the next call like so within your Adapter's getView() :
editText.setId(position + 1); // + 1 so your id is never 0
if(position < getCount() - 1)
editText.setNextFocusDown(position + 2); // the id of the next edit text
else
editText.setImeOptions(EditorInfo.IME_ACTION.DONE);
Theoretically, your ListView will always have built the next item in the list's view unless it is the last item in the list (which you can then set the ime options to done), not 100% on that though. Again, I am not sure if this works but it is obviously too much for a comment.
while I am making a post
For the content of each EditText you could do something like
private SparseArray<String> mEditTextInputs = new SparseArrayt<>();
then in getView(), make position parameter final and try
editText.setText(mEditTextInputs.get(position);
editText.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){
mEditTextInputs.put(position, s.toString());
}
}
This is not the best idea, but in order to do what you ask create a Layout and Populate a ScrollView with EditText so when you select next on keyboard it goes down one EditText:
Here is an example:
https://gist.github.com/lt-tibs1984/5d3e6a50f9d883026014
to go even further each time you do:
int count = 0;
for (String item : items) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.list_item, null);
EditText editText = (EditText)view.findViewById(R.id.editTextDemo);
editText.setText(item);
// set a tag here to uniquely identify it later
editText.setTag(count);
mLinearLayout.addView(view);
count++;
}
Alternative loop:
for (int i = 0 ; i < 25; i++) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.list_item, null);
EditText editText = (EditText)view.findViewById(R.id.editTextDemo);
editText.setText(items.get(i));
// set a tag here to uniquely identify it later
editText.setTag(i);
mLinearLayout.addView(view);
}
I have a ListView containing rows with EditText's.
When I click on an EditText and it's not already focused it receives focus, the keyboard appears and the EditText is moved above the CandidateView (desired behaviour).
However when I make a key press, the EditText maintains focus and receives the input but moves down and is obscured by the keyboard (the previous movement is reversed).
When I click on the EditText when it is already selected without the keyboard shown, the keyboard pops up but the EditText is not moved to the right position (above the CandidateView). It still receives the input.
I add a header view containing EditText's and there everything works correctly.
This is the code of my ArrayAdapter where the row view is created:
View view = inflater.inflate(R.layout.row_profile_entry_text, null);
final String question = getItem(position);
TextView textViewQuestion = (TextView) view.findViewById(R.id.rpeq_TextViewQuestion);
textViewQuestion.setText(question);
final EditText editTextAnswer = (EditText) view.findViewById(R.id.rpeq_EditTextAnswer);
editTextAnswer.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
mAnswers.put(question, s.toString());
}
});
if (mAnswers.containsKey(question)) {
editTextAnswer.setText(mAnswers.get(question));
}
return view;
I would also like to emphasize that I already added
android:windowSoftInputMode="adjustPan" to the Manifest and android:descendantFocusability="beforeDescendants" to the ListView as most of the answers to other questions suggest.
Without adjustPan the EditText is not able to receive focus at all but it does not solve the issue entirely.
Does someone have an idea what I am doing wrong?
Try this:
<activity name="YourActivity"
android:windowSoftInputMode="stateVisible|adjustResize|adjustPan">
</activity>
in the manifest file.
Most probably, adjustResize must work, if you are using a ScrollView.
after many hours spent on this problem this is my solution (for Android < 4.2):
1) Manifest => android:windowSoftInputMode="adjustPan"
2) Activity=> create OnTouchListner and pass to Adapter
private OnTouchListener exampleOnTouchListener = new OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_UP == event.getAction()) {
int position = (Integer) v.getTag();
myListView.setSelection(position);
}
return false;
}
};
3) Adapter
if (exampleOnTouchListener!= null) {
myEditText.setTag(position);
myEditText.setOnTouchListener(exampleOnTouchListener);
// if last element set padding bottom for spacing
if (position == items.size() - 1) {
LinearLayout myLinearLayout = (LinearLayout) convertView
.findViewById(R.id.ticketcontolProposedRealvalueLinearLayout);
myLinearLayout.setPadding(0, 0, 0,SET_PADDING_BOTTOM);
}
}
I have provided an AutoCompleteTextView to show suggestions to the user. Based on the item selected by the user, I am getting the ID of the item and using it in data base side. Now my problem is to force the user to make selection only from AutoCompleteTextView (i.e. user should not enter his own text). It is a client requirement. How to do this?
Here's a pretty straightforward solution:
You can create a variable to store the selected value by setting setOnItemClickListener in your AutoCompleteTextView. Then you can null that value whenever a user types in the field by adding a TextWatcher to it. Finally, you can validate your variable is not null before continuing.
String my_var; //keep track!
AutoCompleteTextView tv = (AutoCompleteTextView) layout.findViewById(R.id.tv);
tv.setAdapter(my_adapter);
tv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
my_var = my_adapter.getItem(position).toString();
}
});
/**
* Unset the var whenever the user types. Validation will
* then fail. This is how we enforce selecting from the list.
*/
tv.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) {
my_var = null;
}
#Override
public void afterTextChanged(Editable s) {}
});
I happened to need such a requirement for a project I am working on, and I though I'll share you guys the way I implemented the required.
I added a on focus change listener for the auto-complete text view and checked when the user has focus changed focus from the auto-complete, and handled the situation straight forward.
autoTextViewCountry.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean b) {
if(!b) {
// on focus off
String str = autoTextViewCountry.getText().toString();
ListAdapter listAdapter = autoTextViewCountry.getAdapter();
for(int i = 0; i < listAdapter.getCount(); i++) {
String temp = listAdapter.getItem(i).toString();
if(str.compareTo(temp) == 0) {
return;
}
}
autoTextViewCountry.setText("");
}
}
});
So my implementation is: if the typed text doesn't exist in the array adapter then on focus changed empty the text view, and later on when continuing to next stage of say registration, check if this text view is empty or not.
Hope this approach helps somebody.
Happy coding.
NiceAutoCompleteTextView will give you the ability to check whether a selection was made from the drop-down popup, by invoking isSelectionFromPopup()
Just add this property to your AutoCompleteTextView.
android:focusable="false"
My Code looks like:
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/menu"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Mode">
<AutoCompleteTextView
android:id="#+id/mode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
/>
</com.google.android.material.textfield.TextInputLayout>
On Java Side:
AutoCompleteTextView mode = findViewById(R.id.mode);
final List<String> modeList = new ArrayList();
modeList.add("YEARLY");
modeList.add("HALF-YEARLY");
modeList.add("QUARTER-YEARLY");
modeList.add("MONTHLY");
mode.setAdapter(new ArrayAdapter(getApplicationContext(),R.layout.list_item,modeList));
To get the Text of AutoCompleteTextView:
mode.getText().toString()
Ok I assume you would like to limit the input of the user to the texts contained in the list of items listed in the suggest box.
For instance if you have:
One
Two
Three
then the user could only type for the first character "O" and "T".
And so on according to the text entered before.
To achieve this you can utilize the setFilters method of TextView:
editBox = (TextView) findViewById(R.id.editBox);
editBox.setFilters(getFilters());
editBox.addTextChangedListener(this);
editBox.setOnFocusChangeListener(this);
Additionally you would probably need the text change listener and focus listener to react and update the filtered list when a new character is entered ... plus to update the filter.
Here is an example of decimal number filter I have used on a project:
protected InputFilter[] getFilters()
{
InputFilter[] filters = new InputFilter[1];
filters[0] = new InputFilter()
{
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
{
// limit input to digits and decimal / thousand separator only
// in case thousand separator is pressed, change it to decimal
// separator instead
String output = "";
if (number.isFocused())
{
for (int i = start; i < end; i++)
{
char c = source.charAt(i);
if (isDecimalOrThousandSeparator(c))
{
output = output + Character.toString(decimalSeparator);
}
else if (Character.isDigit(c))
{
output = output + Character.toString(c);
}
}
return output == "" ? null : output;
}
return null;
}
};
return filters;
}
A simple solution would be to just check if the current input is one of the items in the adapter. You can do it like this:
val AutoCompleteTextView.isValid: Boolean
get() {
for (i in 0 until adapter.count) {
if (adapter.getItem(i) == text.toString()) {
return true
}
}
return false
}
here is the another solution for this proAutoCompleteTextView.Validator to ensure the valid values. Validator is invoked when edit text looses focus.
autoCompleteTextView.validator = object : AutoCompleteTextView.Validator {
override fun isValid(text: CharSequence?): Boolean {
return optionsList.contains(text.toString())
}
override fun fixText(invalidText: CharSequence?): CharSequence {
return ""
}
}
Where optionsList is list of valid values.
I was having the same requirement, so here is my implementation:
autoCompleteTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
autoCompleteTextView.showDropDown();
}
});
In the xml set focusable=false and focusableInTouchMode=false.
Happy coding
In order to have a non editable variation of the AutoCompleteTextView, you should disable user input in the AutoCompleteTextView. That can be achieved by setting android:inputType="none" on the AutoCompleteTextView.
In Android, I create a password field like this:
EditText text = new EditText(context);
text.setTransformationMethod(PasswordTransformationMethod.getInstance());
Or like this, which seems to do the same thing:
EditText text = new EditText(context);
text.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
I get a nice password field except for the last character typed by the user. It's visible on the screen for a few seconds before beeing masked with a dot.
Here is a screenshot:
Do you know how to fix this behaviour please?
This is expected behavior. With the soft keyboards on most devices, it is valuable feedback that they are typing the password correctly.
For a list of all of the different inputTypes you can specify and how they change the EditText,
see android inputTypes .
Also, it is possible to change this behavior by implementing your own TransformationMethod and setting it via setTransformationMethod(), but I would not recommend doing that. Users will expect the behavior you are seeing and by changing your app, you'll be providing an inconsistent user experience.
also check this android article
Implementation of TransformationMethod to hide last char typed in password:
public class LoginActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// example of usage
((TextView) findViewById(R.id.password)).setTransformationMethod(new HiddenPassTransformationMethod());
}
private class HiddenPassTransformationMethod implements TransformationMethod {
private char DOT = '\u2022';
#Override
public CharSequence getTransformation(final CharSequence charSequence, final View view) {
return new PassCharSequence(charSequence);
}
#Override
public void onFocusChanged(final View view, final CharSequence charSequence, final boolean b, final int i,
final Rect rect) {
//nothing to do here
}
private class PassCharSequence implements CharSequence {
private final CharSequence charSequence;
public PassCharSequence(final CharSequence charSequence) {
this.charSequence = charSequence;
}
#Override
public char charAt(final int index) {
return DOT;
}
#Override
public int length() {
return charSequence.length();
}
#Override
public CharSequence subSequence(final int start, final int end) {
return new PassCharSequence(charSequence.subSequence(start, end));
}
}
}
}
I came across this problem after needing to implement a pin-code type user interface. After the user entered 1 number (1:1 relationship between EditTexts and pin numbers for a total of 4 EditTexts) the password would remain "in the open". My solution was to implement a TextWatcher that replaced the input with bullets (•'s).
See the full answer here
I was also facing same issues, in my case there was 3 edit text each edit text can have maximum 4 digit number for Aadhaar number. I used numberPassword input type.
When user type Aadhaar number very fast first edit text last text 4th was not hiding because I am changing focus when 4 digit completed. I have added text watcher.
I got solution at the end of last edit text when 4 digit completed I requestFocus for all 3 edit text one by one.
Solution :
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (getBinding().edtFirstFourNumber.getText().toString().length() == 4 && getBinding().edtMiddleFourNumber.getText().toString().length() == 4 && getBinding().edtLastFourNumber.getText().toString().length() == 4) {
// getBinding().homeProceed.setAlpha(1f);
getBinding().homeProceed.setTextColor(ContextCompat.getColor(mContext, R.color.color_ffffff));
getBinding().homeProceed.setEnabled(true);
} else {
// getBinding().homeProceed.setAlpha(0.5f);
getBinding().homeProceed.setTextColor(ContextCompat.getColor(mContext, R.color.color_4090BE));
getBinding().homeProceed.setEnabled(false);
}
if (getBinding().edtFirstFourNumber.length() == 4) {
getBinding().edtMiddleFourNumber.requestFocus();
}
if (getBinding().edtMiddleFourNumber.length() == 4) {
getBinding().edtLastFourNumber.requestFocus();
}
if (getBinding().edtLastFourNumber.length() == 4) {
getBinding().edtFirstFourNumber.requestFocus();
getBinding().edtMiddleFourNumber.requestFocus();
getBinding().edtLastFourNumber.requestFocus();
CommonUtils.hideSoftKeyboard(getActivity());
}
}