My rows contain a button that has its own click listener set in my adapter's getView. I'm able to distinguish between my button clicks and the actual row item clicks using android:descendantFocusability="blocksDescendants" in the row's parent.
When I click on a button it sets the button background properly, my problem is as I scroll through the list its setting it for different rows as well. I assume theirs an issue somewhere with views recycling.
Here's my code:
@Override
public View getView(int position, View convertView, ViewGroup parent){
if(convertView == null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.todays_sales_favorite_row, null);
holder.favCatBtn = (Button)convertView.findViewById(R.id.favCatBtn);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.favCatBtn.setTag(position);
holder.favCatBtn.setOnClickListener(this);
return convertView;
}
@Override
public void onClick(View v) {
int pos = (Integer) v.getTag();
Log.d(TAG, "Button row pos click: " + pos);
RelativeLayout rl = (RelativeLayout)v.getParent();
holder.favCatBtn = (Button)rl.getChildAt(0);
holder.favCatBtn.setBackgroundResource(R.drawable.icon_yellow_star_large);
}
So if i click on the button at row position 1 the button background changes as it should. But then as i scroll down the list random other buttons are getting set as well. Then sometimes when I scroll back up to position 1 the button background reverts back to the original again.
What am I missing here? I know I'm right there its just something minor I'm not doing.
Yes, you are right, the views are recycled. You will need to track which positions have been clicked on and update the background resource in your getView
method. For example, I extended your code to add background toggling:
private final boolean[] mHighlightedPositions = new boolean[NUM_OF_ITEMS];
@Override
public View getView(int position, View convertView, ViewGroup parent){
if(convertView == null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.todays_sales_favorite_row, null);
holder.favCatBtn = (Button)convertView.findViewById(R.id.favCatBtn);
holder.favCatBtn.setOnClickListener(this);
convertView.setTag(holder);
}else {
holder = (ViewHolder)convertView.getTag();
}
holder.favCatBtn.setTag(position);
if(mHighlightedPositions[position]) {
holder.favCatBtn.setBackgroundResource(R.drawable.icon_yellow_star_large);
}else {
holder.favCatBtn.setBackgroundResource(0);
}
return convertView;
}
@Override
public void onClick(View view) {
int position = (Integer)view.getTag();
Log.d(TAG, "Button row pos click: " + position);
// Toggle background resource
RelativeLayout layout = (RelativeLayout)view.getParent();
Button button = (Button)layout.getChildAt(0);
if(mHighlightedPositions[position]) {
button.setBackgroundResource(0);
mHighlightedPositions[position] = false;
}else {
button.setBackgroundResource(R.drawable.icon_yellow_star_large);
mHighlightedPositions[position] = true;
}
}
I found a perfect, short and clean solution for this using StateListDrawable:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
currentPosition = position;
holder = null;
if (convertView == null) {
holder = new Holder();
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.grid_item, null);
holder.imageView = (ImageView) convertView.findViewById(R.id.gridItemBtn);
StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed},
ContextCompat.getDrawable(context, R.drawable.pressed_state));
states.addState(new int[] {android.R.attr.state_focused},
ContextCompat.getDrawable(context, R.drawable.focused_state));
states.addState(new int[]{},
ContextCompat.getDrawable(context, R.drawable.default_state));
holder.imageView.setImageDrawable(states);
}
return convertView;
}
This works still perfect together with OnClickListener where you can do your important stuff.
holder.btnUnLock.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// Button btn = Button(v);
holder = (ViewHolder) v.getTag();
holder.btnSetLock.setBackgroundResource(R.drawable.btn_lock_bg_right);
holder.btnUnLock.setBackgroundResource(R.drawable.btn_unlock_bg_left);
}
});