0

トグルボタン、スピナー、その他のビューを備えたカスタムアダプターを備えたリストビューがあります。

このリストビューには、通常 1 つの画面に収まるよりも多くの項目が表示されます。これにより、私には理解できない奇妙な問題が発生します。

例: リストの最初の項目のトグル ボタンを押すと、背景の色が変わります。次に「2番目の画面」(アイテム10〜18)まで下にスクロールすると、背景も変更されたため、11番目のアイテムも「トグル」されていることがわかります。さらに下にスクロールすると、20 番目の項目も選択されています。

私のアダプターは次のようになります。

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);
        }

    }
};
}
4

2 に答える 2

2

Alex.F が指摘したように、問題は ListView のリサイクル動作です。解決策は非常に簡単です。

ラインアイテムには、色の状態に対応するブール値が既にあります。これを使用します。

RetourArticleListener で、if-else ステートメントを次のように変更します。

if (on) {
     // Article returned
     lineList.get(position).setLineArticleReturned(true);
     notifyDatasetChanged();
} else {
     // Article used
     lineList.get(position).setLineArticleReturned(false);
     notifyDatasetChanged();
}

notifyDatasetChanged メソッドは、getView() メソッドが確実に呼び出されるようにします。

getView() メソッドで、「LineArticleReturned」の値を確認し、それに応じて背景色を変更します。これを getView メソッドの末尾のどこかに追加して、それまでに必要なすべての変数が確実に初期化されるようにします。Line クラスに LineArticleReturned のブール値を返す getLineArticleReturned() というメソッドがあるとします。

 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);
 }
于 2015-02-12T16:13:39.157 に答える
1

これは、listView のリサイクル メカニズムの問題の明らかなケースです。たとえば、このSO Q&Aでそれを読む必要があります

于 2015-02-12T14:52:16.670 に答える