Reputation: 229
I have a listview with custom adaptor with a toggle button, a spinner and some other views in it.
This listview shows more items than can normally fit on 1 screen and this causes a weird problem which I don't understand.
For example: When I press the toggle button of the first item in the list, the background changes color. If I then scroll downwards to the "2nd screen" (items 10-18) I notice that the 11th item has also been "toggled" as the background has also changed. If I then scroll down even further downwards to the 20th item has also been selected.
My adapter looks like this:
public class ArticlesListAdapter extends ArrayAdapter<Line> {
private List<Line> lineList;
private Context context;
public ArticlesListAdapter(Context context, int textViewResourceId,
List<Line> objects) {
super(context, textViewResourceId, objects);
this.lineList = objects;
this.context = context;
}
public int getCount() {
return lineList.size();
}
public Line getItem(int position) {
return lineList.get(position);
}
public long getItemId(int position) {
return position;
}
public List<Line> GetAllLines() {
return lineList;
}
@SuppressLint("InflateParams")
public View getView(int position, View convertView, ViewGroup parent) {
Viewholder viewholder;
if (convertView == null) {
viewholder = new Viewholder();
convertView = LayoutInflater.from(context).inflate(
R.layout.articles_list_row, null);
viewholder.articleName = (TextView) convertView
.findViewById(R.id.textArticleName);
viewholder.articleAmount = (EditText) convertView
.findViewById(R.id.textArticleAmount);
viewholder.articleButton = (ToggleButton) convertView
.findViewById(R.id.toggleArticleReturn);
viewholder.articleStock = (Spinner) convertView
.findViewById(R.id.spinStockWarehouse);
convertView.setTag(viewholder);
} else {
viewholder = (Viewholder) convertView.getTag();
}
viewholder.articleButton.setTag(position);
if (lineList.get(position).getLineCode().length() > 0) {
viewholder.articleButton.setOnClickListener(RetourArticleListener);
viewholder.articleButton.setOnLongClickListener(RetourCertainAmountArticleListener);
} else {
viewholder.articleButton.setText("Delete");
viewholder.articleButton.setOnClickListener(DeleteArticleListener);
}
String articleNameString = lineList.get(position)
.getLineArticleDescription();
if (articleNameString.length() > 30) {
articleNameString.substring(0, 30);
}
viewholder.articleName.setText(articleNameString);
viewholder.articleName.setTextSize(12);
viewholder.articleAmount.setTag(position);
viewholder.articleAmount.setTextSize(12);
viewholder.articleAmount.setText(lineList.get(position)
.getLineArticleAmount().toString());
if (lineList.get(position).isLineArticleIsOriginal()) {
viewholder.articleStock.setEnabled(false);
}
viewholder.articleStock.setSelection(Integer.parseInt(lineList
.get(position).getLineArticleStock().toString()) - 1);
viewholder.articleStock.setTag(position);
viewholder.articleStock
.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView,
View view, int position, long id) {
final int listPosition = (Integer) adapterView.getTag();
lineList.get(listPosition).setLineArticleStock(
String.valueOf(position + 1));
}
@Override
public void onNothingSelected(AdapterView<?> adapter) {
}
});
// we need to update adapter once we finish with editing
viewholder.articleAmount
.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
final int position = (Integer) v.getTag();
final EditText articleAmount = (EditText) v;
lineList.get(position).setLineArticleAmount(
Double.parseDouble(articleAmount.getText()
.toString().replace(",", ".")));
}
}
});
return convertView;
}
private OnClickListener RetourArticleListener = new OnClickListener() {
@Override
public void onClick(View v) {
boolean on = ((ToggleButton) v).isChecked();
int position = (Integer) v.getTag();
RelativeLayout rl = (RelativeLayout) v.getParent();
if (on) {
// Article returned
rl.setBackgroundColor(Color.RED);
lineList.get(position).setLineArticleReturned(true);
} else {
// Article used
rl.setBackgroundColor(Color.WHITE);
lineList.get(position).setLineArticleReturned(false);
}
}
};
}
Upvotes: 0
Views: 418
Reputation: 1306
The problem, as pointed out by Alex.F, is the recycling behavior of the ListView. The solution is pretty simple:
You Line item already has a boolean that corresponds to the color state, which we'll use.
In your RetourArticleListener, change the if-else statement to:
if (on) {
// Article returned
lineList.get(position).setLineArticleReturned(true);
notifyDatasetChanged();
} else {
// Article used
lineList.get(position).setLineArticleReturned(false);
notifyDatasetChanged();
}
The notifyDatasetChanged method will make sure your getView() method is called.
In your getView() method, check the value for "LineArticleReturned" and change the background color accordingly. Add this somewhere at the end of your getView method so you're sure all required variables are initialized by then. I assume you have a method called getLineArticleReturned() which returns the boolean value of LineArticleReturned in your Line class.
if(lineList.get(position).getLineArticleReturned()==true){
RelativeLayout rl = (RelativeLayout)
convertView.findViewById(R.id.name_of_your_relative_layout_here);
rl.setBackgroundColor(Color.RED);
}else{
rl.setBackgroundColor(Color.WHITE);
}
Upvotes: 2
Reputation: 6181
This is a clear case of an issue with listView's recycling mechanism. You should read up on it for example in this SO Q&A
Upvotes: 1