Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom ListView click issue on items in Android

So I have a custom ListView object. The list items have two textviews stacked on top of each other, plus a horizontal progress bar that I want to remain hidden until I actually do something. To the far right is a checkbox that I only want to display when the user needs to download updates to their database(s). When I disable the checkbox by setting the visibility to Visibility.GONE, I am able to click on the list items. When the checkbox is visible, I am unable to click on anything in the list except the checkboxes. I've done some searching but haven't found anything relevant to my current situation. I found this question but I'm using an overridden ArrayAdapter since I'm using ArrayLists to contain the list of databases internally. Do I just need to get the LinearLayout view and add an onClickListener like Tom did? I'm not sure.

Here's the listview row layout XML:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="fill_parent"     android:layout_height="?android:attr/listPreferredItemHeight"     android:padding="6dip">     <LinearLayout         android:orientation="vertical"         android:layout_width="0dip"         android:layout_weight="1"         android:layout_height="fill_parent">         <TextView             android:id="@+id/UpdateNameText"             android:layout_width="wrap_content"             android:layout_height="0dip"             android:layout_weight="1"             android:textSize="18sp"             android:gravity="center_vertical"             />         <TextView             android:layout_width="fill_parent"             android:layout_height="0dip"             android:layout_weight="1"             android:id="@+id/UpdateStatusText"             android:singleLine="true"             android:ellipsize="marquee"             />         <ProgressBar android:id="@+id/UpdateProgress"                       android:layout_width="fill_parent"                       android:layout_height="wrap_content"                      android:indeterminateOnly="false"                       android:progressDrawable="@android:drawable/progress_horizontal"                       android:indeterminateDrawable="@android:drawable/progress_indeterminate_horizontal"                       android:minHeight="10dip"                       android:maxHeight="10dip"                                          />     </LinearLayout>     <CheckBox android:text=""                android:id="@+id/UpdateCheckBox"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                /> </LinearLayout> 

And here's the class that extends the ListActivity. Obviously it's still in development so forgive the things that are missing or might be left laying around:

public class UpdateActivity extends ListActivity {      AccountManager lookupDb;     boolean allSelected;     UpdateListAdapter list;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);          lookupDb = new AccountManager(this);         lookupDb.loadUpdates();          setContentView(R.layout.update);         allSelected = false;          list = new UpdateListAdapter(this, R.layout.update_row, lookupDb.getUpdateItems());         setListAdapter(list);          Button btnEnterRegCode = (Button)findViewById(R.id.btnUpdateRegister);         btnEnterRegCode.setVisibility(View.GONE);          Button btnSelectAll = (Button)findViewById(R.id.btnSelectAll);         btnSelectAll.setOnClickListener(new Button.OnClickListener() {             @Override             public void onClick(View v) {                 allSelected = !allSelected;                  for(int i=0; i < lookupDb.getUpdateItems().size(); i++) {                     lookupDb.getUpdateItem(i).setSelected(!lookupDb.getUpdateItem(i).isSelected());                 }                  list.notifyDataSetChanged();                 // loop through each UpdateItem and set the selected attribute to the inverse               } // end onClick         }); // end setOnClickListener          Button btnUpdate = (Button)findViewById(R.id.btnUpdate);         btnUpdate.setOnClickListener(new Button.OnClickListener() {             @Override             public void onClick(View v) {             } // end onClick         }); // end setOnClickListener          lookupDb.close();     } // end onCreate       @Override     protected void onDestroy() {         super.onDestroy();          for (UpdateItem item : lookupDb.getUpdateItems()) {             item.getDatabase().close();                 }     }      @Override     protected void onListItemClick(ListView l, View v, int position, long id) {         super.onListItemClick(l, v, position, id);          UpdateItem item = lookupDb.getUpdateItem(position);          if (item != null) {             item.setSelected(!item.isSelected());             list.notifyDataSetChanged();         }     }      private class UpdateListAdapter extends ArrayAdapter<UpdateItem> {         private List<UpdateItem> items;          public UpdateListAdapter(Context context, int textViewResourceId, List<UpdateItem> items) {             super(context, textViewResourceId, items);             this.items = items;         }          @Override         public View getView(int position, View convertView, ViewGroup parent) {             View row = null;              if (convertView == null) {                 LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);                 row = li.inflate(R.layout.update_row, null);             } else {                 row = convertView;             }              UpdateItem item = items.get(position);              if (item != null) {                 TextView upper = (TextView)row.findViewById(R.id.UpdateNameText);                 TextView lower = (TextView)row.findViewById(R.id.UpdateStatusText);                 CheckBox cb = (CheckBox)row.findViewById(R.id.UpdateCheckBox);                  upper.setText(item.getName());                 lower.setText(item.getStatusText());                  if (item.getStatusCode() == UpdateItem.UP_TO_DATE) {                     cb.setVisibility(View.GONE);                 } else {                     cb.setVisibility(View.VISIBLE);                     cb.setChecked(item.isSelected());                 }                  ProgressBar pb = (ProgressBar)row.findViewById(R.id.UpdateProgress);                 pb.setVisibility(View.GONE);             }             return row;         }      } // end inner class UpdateListAdapter } 

edit: I'm still having this problem. I'm cheating and adding onClick handlers to the textviews but it seems extremely stupid that my onListItemClick() function is not being called at all when I am not clicking on my checkbox.

like image 211
MattC Avatar asked Jul 13 '09 18:07

MattC


2 Answers

The issue is that Android doesn't allow you to select list items that have elements on them that are focusable. I modified the checkbox on the list item to have an attribute like so:

android:focusable="false" 

Now my list items that contain checkboxes (works for buttons too) are "selectable" in the traditional sense (they light up, you can click anywhere in the list item and the "onListItemClick" handler will fire, etc).

EDIT: As an update, a commenter mentioned "Just a note, after changing the visibility of the button I had to programmatically disable the focus again."

like image 188
MattC Avatar answered Oct 06 '22 02:10

MattC


In case you have ImageButton inside the list item you should set the descendantFocusability value to 'blocksDescendants' in the root list item element.

android:descendantFocusability="blocksDescendants" 

And the focusableInTouchMode flag to true in the ImageButton view.

android:focusableInTouchMode="true" 
like image 30
micnoy Avatar answered Oct 06 '22 00:10

micnoy