问题
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.
回答1:
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;
}
}
回答2:
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.
回答3:
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);
}
});
来源:https://stackoverflow.com/questions/8073990/android-change-button-background-in-listview-row-with-onclick