Friday, March 23, 2012

Enable Button Inside A List Item

Probably most of us needed this kind of rich ListView items that contains several views including buttons. For example when you're building an iOS like ListView that have "Delete" buttons in every list item.

Having a button means that you need to listen the click events on that button. But, if the button is inside a list item, you can not simply sense the clicks to the button, because ListView's OnItemClickListener overwhelms all the click events on that item. In order to avoid this and make your button clickable you need to do the following changes...

At first you need to set android:focusable and android:focusableInTouchMode attributes of your button inside the list item to "false".

<Button
 .....
 android:focusable="false"
 android:focusableInTouchMode="false"
 .....
 >
</Button>

The next thing you need to do is setting an OnClickListener to your button inside your list adapter class. You can achieve this by adding a parameter to your adapter's constructor and/or adding a setter method to the adapter that sets the button's OnClickListener.

In my example I put an OnClickListener instance as a field in my adapter and I set it in my constructor and also added a setter for the field.



public class MyAdapter extends BaseAdapter {
 .....
 public OnClickListener listener;

 .....
 public MyAdapter (Context context, OnClickListener listener) {
  this.context = context;
  mInflater = LayoutInflater.from(this.context);
  this.listener = listener;
 }

 public void setButtonListener(OnClickListener listener) {
  this.listener = listener;
 }

 .....

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  
  if (convertView == null) {
   convertView = 
    mInflater.inflate(R.layout.my_list_row, null);

   holder = new ViewHolder();
   ...
   holder._button = 
    (Button) convertView
     .findViewById(R.id.listRowButton);
   ...
   convertView.setTag(holder);

  } else {
   holder = (ViewHolder) convertView.getTag();
  }

  .....

  if (this.listener != null) {
   holder._button.setOnClickListener(this.listener);
  }
  .....
 }
}


And lastly you need to set an OnClickListener to your adapter instance where you set your ListView's adapter inside your Activity. And this is the tricky part that you need to sense which list item's button has received a click event by by using a for loop. (It doesn't look so efficient, but this was the easiest way to achieve my goal, so I did it like this. If you have any other efficient solutions please provide a comment.)


ListView myList = (ListView) findViewById(R.id.myList);

// Firstly I set the OnClickListener as null.
MyAdapter adapter = new MyAdapter(this, null);

.....
// Here is where I set the listener for button inside list item.
myAdapter.setButtonListener(new OnClickListener() {

 @Override
 public void onClick(View v) {
  for (int i = 0; i < _listView.getChildCount(); i++) {
   if (v == _listView
    .getChildAt(i).findViewById(R.id.listRowButton))
   {

    // Do Something on Button Click

   }
  }
 }
}});
.....

myList.setAdapter(myAdapter);


That's it! You can do whatever with your list item's button now. You can also use the same procedure with CheckBoxes, RadioButtons or any other Views.

Enjoy!

1 comment:

  1. This is because the 20lbs isn’t really “Halotest” it is in fact cellular water (which is different from estrogen water retention).

    ReplyDelete