Reputation: 289
I have created a Custom Adapter for a ListView and each element in the listview has 1 TextView and 1 Button
..(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
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
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