Ravindra
Ravindra

Reputation: 289

Set isClickable to false for a button in the ListView after the first click Android

I have created a Custom Adapter for a ListView and each element in the listview has 1 TextView and 1 Button

ListView

[TextView 1] [Button 1]

[TextView 2] [Button 2]

..(so on)

My requirement: You are allowed to click button only once. It's like 'Like' button.After the first click, isClickable only for the button in that row should be set to false.

Mycode:

@Override
public View getView(final int position, View convertView, final ViewGroup   parent)  {      
    View row=convertView; 
    ViewHolder holder=null;
    if(row==null)
    {                   
        row=msgInflator.inflate(R.layout.row,parent,false);
        holder = new ViewHolder(row);
        holder.msg=(TextView)row.findViewById(R.id.message_text);
        holder.up=(Button)row.findViewById(R.id.upVote);

        holder.up.setTag(holder);
        holder.up.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                ViewHolder hold=(ViewHolder)v.getTag();
                hold.up.setClickable(false);
            }
        });
        row.setTag(holder);         
    }
    else
    {
        holder=(ViewHolder)row.getTag();            
    }   
    holder.msg.setText(messages.get(position).getMessage());
    holder.up.setText(messages.get(position).getUp());
    return row;
}

Problem:

When i click on Button 1:

Button 1 isClickable set to false -> which is required

Few other Buttons (ex: Button 5,6) isClickable is also set to false -> Which is undesired

How can i achieve my required output?

Upvotes: 0

Views: 6252

Answers (2)

Amulya Khare
Amulya Khare

Reputation: 7698

Here is my solution, with two main changes:

1) Maintain a list of button positions that have been disabled. Every time, you click on a button, store its position in the list.

2) Move the onClickListener out of if/else and set it every time. This ensures that despite views being reused, the position is up-to-date.

ArrayList<Integer> positions = new ArrayList<Integer>();

@Override
public View getView(final int position, View convertView, final ViewGroup   parent)  {      
    View row=convertView; 
    ViewHolder holder=null;
    if(row==null)
    {                   
        row=msgInflator.inflate(R.layout.row,parent,false);
        holder = new ViewHolder(row);
        holder.msg=(TextView)row.findViewById(R.id.message_text);
        holder.up=(Button)row.findViewById(R.id.upVote);

        row.setTag(holder);         
    }
    else
    {
        holder=(ViewHolder)row.getTag();            
    }   
    holder.msg.setText(messages.get(position).getMessage());
    holder.up.setText(messages.get(position).getUp());
    holder.up.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Button btn = (Button)v;
            btn.setClickable(false);
            positions.add(position)
        }
    });
    if(positions.contains(new Integer(position))) {
        holder.up.setClickable(false);
    }
    return row;
}

Upvotes: 2

Cheok Yan Cheng
Cheok Yan Cheng

Reputation: 42670

This is due to the behavior of ListView. To have ListView performs as optimized as possible, Android team deploys View reusing technique in ListView intensively.

This mean, the Button you're using in row N, may be reuse again in row N+12. So, you need to update your Button's state everytime getView is being triggered.

Here's what you can do.

    if (off.contains(position)) {
        hold.up.setClickable(false);
    } else {
        hold.up.setClickable(true);
    }

    if (row==null)
    {   
        ...
        holder.up.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // off is Set<Integer>
                off.add(position);
            }
        });
        ....

Upvotes: 1

Related Questions