EditText inside ListView will not stay focused
EditText
s within ListView
s are extremely tricky. I'd suggest you avoid them like the plague if possible. When I was messing with them, this answer was helpful though. If you only have a few items you can always just use a ScrollView
.
Focusable EditText inside ListView
Sorry, answered my own question. It may not be the most correct or most elegant solution, but it works for me, and gives a pretty solid user experience. I looked into the code for ListView to see why the two behaviors are so different, and came across this from ListView.java:
public void setItemsCanFocus(boolean itemsCanFocus) {
mItemsCanFocus = itemsCanFocus;
if (!itemsCanFocus) {
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
}
So, when calling setItemsCanFocus(false)
, it's also setting descendant focusability such that no child can get focus. This explains why I couldn't just toggle mItemsCanFocus
in the ListView's OnItemSelectedListener -- because the ListView was then blocking focus to all children.
What I have now:
<ListView
android:id="@android:id/list"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:descendantFocusability="beforeDescendants"
/>
I use beforeDescendants
because the selector will only be drawn when the ListView itself (not a child) has focus, so the default behavior needs to be that the ListView takes focus first and draws selectors.
Then in the OnItemSelectedListener, since I know which header view I want to override the selector (would take more work to dynamically determine if any given position contains a focusable view), I can change descendant focusability, and set focus on the EditText. And when I navigate out of that header, change it back it again.
public void onItemSelected(AdapterView<?> listView, View view, int position, long id)
{
if (position == 1)
{
// listView.setItemsCanFocus(true);
// Use afterDescendants, because I don't want the ListView to steal focus
listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
myEditText.requestFocus();
}
else
{
if (!listView.isFocused())
{
// listView.setItemsCanFocus(false);
// Use beforeDescendants so that the EditText doesn't re-take focus
listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
listView.requestFocus();
}
}
}
public void onNothingSelected(AdapterView<?> listView)
{
// This happens when you start scrolling, so we need to prevent it from staying
// in the afterDescendants mode if the EditText was focused
listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
Note the commented-out setItemsCanFocus
calls. With those calls, I got the correct behavior, but setItemsCanFocus(false)
caused focus to jump from the EditText, to another widget outside of the ListView, back to the ListView and displayed the selector on the next selected item, and that jumping focus was distracting. Removing the ItemsCanFocus change, and just toggling descendant focusability got me the desired behavior. All items draw the selector as normal, but when getting to the row with the EditText, it focused on the text field instead. Then when continuing out of that EditText, it started drawing the selector again.
Focus on wrong edit text inside listview
Finally, I figured it out. the problem was trying to solve get tex changed value inside getview. This was re-rendering the list items and I was getting wrong focus and different weird behavious. I have created a textwatcher class and added it while initializing the object, so that it doesn't affect everytime for each item in the list. Below is the code for MyCustom Adapter
public class OrderViewListAdapter extends ArrayAdapter<OrderItemList> {
public OrderViewListAdapter(Context context, int resource) {
super(context, resource);
}
private class ViewHolder {
TextView sku_desc;
TextView uom_desc;
EditText order_qty;
ImageButton plus;
ImageButton minus;
AutoCompleteTextView uom;
MyCustomEditTextListener myCustomEditTextListener;
public ViewHolder(View convertView, MyCustomEditTextListener myCustomEditTextListener) {
this.myCustomEditTextListener = myCustomEditTextListener;
this.order_qty = (EditText) convertView.findViewById(R.id.number_of_item);
this.order_qty.addTextChangedListener(myCustomEditTextListener);
}
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// Get the data item for this position
OrderItemList vehicleTransit = mDataSet.get(position);
//System.out.println("kamal123" +mDataSet.get(position).getOrderID());
System.out.println("kamal123" +position);
ViewHolder viewHolder;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.list_item_selector, parent, false);
viewHolder = new ViewHolder(convertView, new MyCustomEditTextListener());
viewHolder.sku_desc = (TextView) convertView.findViewById(R.id
.item_name);
viewHolder.uom_desc = (TextView) convertView.findViewById(R.id
.uom_desc);
viewHolder.order_qty = (EditText) convertView.findViewById(R.id.number_of_item);
viewHolder.plus= (ImageButton)convertView.findViewById(R.id.button_plus) ;
viewHolder.minus= (ImageButton)convertView.findViewById(R.id.button_minus) ;
convertView.setTag(viewHolder);
viewHolder.plus.setTag(viewHolder);
viewHolder.minus.setTag(viewHolder);
viewHolder.order_qty.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if(vehicleTransit!= null) {
System.out.println("kamal123" + vehicleTransit.getExpectedDeliveryDate()
.toString());
if (vehicleTransit.getExpectedDeliveryDate() != null) {
viewHolder.uom_desc.setText(vehicleTransit.getUOMDesc()
.toString());
System.out.println("kamal123" +vehicleTransit.getExpectedDeliveryDate()
.toString());
}if (vehicleTransit.getSkuDesc() != null) {
viewHolder.sku_desc.setText(vehicleTransit.getSkuDesc().toString());
}
viewHolder.myCustomEditTextListener.updatePosition(position);
viewHolder.order_qty.setText(vehicleTransit.getOrderQty()+"");
viewHolder.order_qty.setId(position);
}
viewHolder.plus.setOnClickListener(new View.OnClickListener() {
int count=0;
@Override
public void onClick(View v) {
View p = (View) v.getParent();
ViewHolder holder1 = (ViewHolder) v.getTag();
count = Integer.valueOf(holder1.order_qty.getText().toString());
count++;
holder1.order_qty.setText(String.valueOf(count));
mDataSet.get(position).setOrderQty(count);
//mAdapter.notifyDataSetChanged();
}
});
viewHolder.minus.setOnClickListener(new View.OnClickListener() {
int count=0;
@Override
public void onClick(View v) {
View p = (View) v.getParent();
ViewHolder holder1 = (ViewHolder) v.getTag();
count = Integer.valueOf(holder1.order_qty.getText().toString());
count--;
if(count>=0)
{holder1.order_qty.setText(String.valueOf(count));
mDataSet.get(position).setOrderQty(count);
//mAdapter.notifyDataSetChanged();
}
}
});
return convertView;
}
private class MyCustomEditTextListener implements TextWatcher {
private int position;
public void updatePosition(int position) {
this.position = position;
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
// no op
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
if (!charSequence.toString().equals("")) {
mDataSet.get(position).setOrderQty(Integer.valueOf(charSequence.toString()));
} else {
mDataSet.get(position).setOrderQty(0);
}
}
@Override
public void afterTextChanged(Editable editable) {
// no op
}
}
@Override
public int getCount() {
return mDataSet.size();
}
}
Issues focusing EditTexts in a ListView (Android)
You are facing ListView
recycling issue. When you scroll up or down or when keyboard appears ListView
again refreshes and lost your EditText's
focus. So, first of all read this answer to understand ListView
Recycling mechanism and then follow the suggestion from my side the solution of your current scenario in my mind.
I suggest you should use a Button
on ListView
Item and text of this button should be generic like Enter Student Info or what ever you'd like. After clicking on this Button
open AlertDialog
and set your xml view (currently your all edittexts
like et_gpa, et_min, et_max etc on listview
items)
For Example:
btnInfo.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
showStudentInfoAlert();
}
});
public void showStudentInfoAlert()
{
AlertDialog.Builder builder = new AlertDialog.Builder(context);
LayoutInflater in = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = in.inflate(R.layout.your_xml_having_edittexts, null);
EditText et_gpa = (EditText) v.findViewById(R.id.et_gpa);
//add all edit texts like this and after that just set view on alert dialog
builder.setTitle("Enter student's info");
builder.setView(v);
builder.setPositiveButton("Save", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//save all edittexts values and do what erver you want with those values
}
});
dialog.show();
}
EditText inside ListView lost focus
I have seen that some solutions are using:
android:descendantFocusability="beforeDescendants"
in the layout of the definition of the list.
For me this wasn't necessary. The problem was fixed using android:windowSoftInputMode="adjustPan":
<activity
android:name="mainActivity"
android:windowSoftInputMode="adjustPan"
android:label="@string/app_name" >
</activity>
in the Manifest.xml.
But you have to make sure that this line of code goes in the activity where you are defining the TabHost or TabActivity!!!.
EditText in Listview loses focus when pressed on Android 4.x
A classic hack for situations like this is to use a handler and postDelayed()
. In your adapter:
private int lastFocussedPosition = -1;
private Handler handler = new Handler();
public View getView(final int position, View convertView, ViewGroup parent) {
// ...
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (lastFocussedPosition == -1 || lastFocussedPosition == position) {
lastFocussedPosition = position;
edittext.requestFocus();
}
}
}, 200);
} else {
lastFocussedPosition = -1;
}
}
});
return convertView;
}
This works on my device, but keep this code out of production. I also wouldn't be surprised if the focus bug manifests itself differently in different android versions or roms.
There are also many other problems with embedding an EditText
within a ListView
that have solutions that feel like a hack. See all of the other people struggling.
It's also very easy to have something like this happen:
.
After having gone down similar paths many times myself, I've mostly given up on trying to override any of the default keyboard behaviours or quirks. I would recommend trying to find alternative solution in your app if possible.
Have you considered having the ListView
rows be just a styled TextView
and then displaying a Dialog
with an EditText
when a row is clicked, updating the TextView as necessary?
Related Topics
Firebase Android: Make Username Unique
How to Pick an Image from Gallery (Sd Card) For My App
Getting the Absolute File Path from Content Uri For Searched Images
How to Install Google Play Services in a Genymotion Vm (With No Drag and Drop Support)
How to Scale an Image in Imageview to Keep the Aspect Ratio
Getting Exception "Illegalstateexception: Can Not Perform This Action After Onsaveinstancestate"
Download Binary File from Okhttp
Android Sqlite Database: Slow Insertion
"Android.View.Windowmanager$Badtokenexception: Unable to Add Window" on Buider.Show()
Android 8.0: Java.Lang.Illegalstateexception: Not Allowed to Start Service Intent
Running Multiple Asynctasks At the Same Time - Not Possible
Onactivityresult Method Is Deprecated, What Is the Alternative
How to Display an Alert Dialog on Android
Filter Logcat to Get Only the Messages from My Application in Android
Same Navigation Drawer in Different Activities