rv.
rv.

Reputation: 81

ListView Adapter behaving weirdly. Unrelated buttons in the ListView get clicked after i click on a button in the same ListView

So, what I want is to individually disable a button for the concerned item in the ListView when clicked on the button itself. This should work for multiple buttons as well.

I tried many places for solutions but didn't get a good enough answer.

What's happening is when i click on a button in the listview, i see other buttons getting clicked automatically when i scroll down to see other buttons which is quite weird and not helping the situation.

This is the Adapter.

public class ListViewAdapter extends BaseAdapter implements ListAdapter {

private ArrayList<String> list = new ArrayList<String>();
private Context context;
private StringBuilder user_id;
private Button sendReq;
private ListViewAdapter adapter;
private JSONArray peopleArray;
private int selectedIndex;
private ViewHolder viewHolder;
private static boolean[] buttonsClicked;
private View rowView;

public ListViewAdapter(ArrayList<String> list, Context context,String user_id,JSONArray jsonArray) {
    this.user_id = new StringBuilder(user_id.toString());
    this.list = list;
    this.context = context;
    peopleArray = jsonArray;
    selectedIndex = -1;
    this.adapter = this;
    buttonsClicked = new boolean[list.size()];
}

@Override
public int getCount() {
    return list.size();
}

@Override
public Object getItem(int pos) {
    return list.get(pos);
}

@Override
public long getItemId(int pos) {
    //return list.get(pos).getId();
    //just return 0 if your list items do not have an Id variable.
    return 0;
}

@Override
public boolean isEnabled(int position){
    return false;
}

static class ViewHolder{
    public TextView ItemText;
    public Button ItemButton;
}

public void setSelectedIndex(int index){
    selectedIndex = index;
    notifyDataSetChanged();
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    rowView = convertView;

    if (rowView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.my_custom_list_layout, null);
        //configure view holder
        viewHolder = new ViewHolder();
        viewHolder.ItemText = (TextView) rowView.findViewById(R.id.list_item_text);
        viewHolder.ItemButton = (Button) rowView.findViewById(R.id.list_item_button);
        rowView.setTag(viewHolder);
    }
    else {
        //fill data
        viewHolder = (ViewHolder) rowView.getTag();
    }
    //Handle TextView and display string from your list
    TextView listItemText = (TextView)rowView.findViewById(R.id.list_item_text);
    listItemText.setText(list.get(position));

    //Handle buttons and add onClickListeners
    sendReq = (Button) rowView.findViewById(R.id.list_item_button);

    viewHolder.ItemButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            //do something
            //list.remove(position); //or some other task

            Log.d("Button position: ", " " +  position);
            ((Button)v).setEnabled(false);
            notifyDataSetChanged();
        }
    });

    return rowView;
}
}

This is the layout

<?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="60dp"
android:weightSum="100"
android:orientation="horizontal">

    <ImageView
        android:id="@+id/list_item_image"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="20"
        android:src="@drawable/default_picture"/>

    <TextView
        android:id="@+id/list_item_text"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:layout_weight="50"
        android:textSize="18sp"
        android:textStyle="bold" />

    <Button
        android:id="@+id/list_item_button"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="30"
        android:text="Send Req"
        android:focusable="false"/>

</LinearLayout>

This is how I am using the adapter in an activity

arrayList.add("Never");
arrayList.add("let");
arrayList.add("anyone");
arrayList.add("make");
arrayList.add("you");
arrayList.add("that");
arrayList.add("you");
arrayList.add("have");
arrayList.add("limits");
myAdapter = new ListViewAdapter(arrayList,this,"",jsonArray);
listview.setAdapter(myAdapter);

Upvotes: 3

Views: 275

Answers (1)

David Wasser
David Wasser

Reputation: 95656

When you click a button, it will disable one Button. Then, when you scroll, that Button will get recycled and reused by other items. You never reenable that Button, so after a while, scrolling up and down, all your Buttons will be disabled.

This isn't the correct way to do this. You cannot make changes in any View based on some action that the user makes (like clicking a button) because the Views in a ListView all get recycled and reused for different list items. When the user takes some action you need to change your data. In getView() you need to use the data to set the state of the Views.

In your case, you could do something like this:

  • Add a private boolean[] enabled array as a member variable in the adapter.
  • Initialize the array in your adapter constructor like this:

    enabled = new boolean[list.size()]; // Enable all items for (int k = 0; k < enabled.length; k++) { enabled[k] = true; }

  • In your onClick() method, do this instead of disabling the Button:

    enabled[position] = false; notifyDataSetChanged();

  • In getView(), set the Button enabled state based on your data like this:

    viewHolder.ItemButton.setEnabled(enabled[position]);

Upvotes: 2

Related Questions