3

リストビューをスクロールすると、リストビューが並べ替えられます。これは非常に混乱します。

これが私が使用しているカスタムアダプタです:

    public class LoadExpenseList extends BaseAdapter{
        List<Expense> expenses;
        Context context;

        public LoadExpenseList(Context context, int textViewResourceId,
                List<Expense> expenses) {
            super();
            this.expenses = expenses;
            this.context = context;
        }

        public View getView(final int position, View convertView, ViewGroup parent){
            //View v = convertView;
            AvailableExpenseView btv;

            if (convertView == null) {
                btv = new AvailableExpenseView(context, expenses.get(position));
            } else {
                btv = (AvailableExpenseView) convertView;
            }           
            btv.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Log.i("Expense_Availables", "Item Selected!!");
                    Intent intent = new Intent(getActivity(), ItemDetailActivity.class);

                    int id = expenses.get(position).getExpenseItemId();
                    intent.putExtra("id", id);

                    startActivity(intent);
                }

            });

            btv.setOnLongClickListener(new OnLongClickListener() {

                @Override
                public boolean onLongClick(View arg0) {
                    // TODO Auto-generated method stub
                    return false;
                }

            });

            registerForContextMenu(btv);

            return btv;
        }

        @Override
        public int getCount() {
            return expenses.size();
        }

        @Override
        public Object getItem(int position) {
            return expenses.get(position);
        }

        @Override
        public long getItemId(int position) {
            return expenses.get(position).getExpenseItemId();
        }

    }
4

3 に答える 3

4

ビュー(AvailableExpenseView)はアイテムで構成されているため、アダプターがconvertViewを介してビューを再利用しようとすると、すでに別のアイテムに関連付けられているビューが取得されます。

モデルアイテムを使用してビューを作成するのではなく、のようなものを呼び出しますconvertView.setExpense(expenses.get(position))

ListViewは、パフォーマンスを向上させるためにビューを再利用しようとします。したがって、リストの最初のアイテムは新しく作成されたビューで表示され、後でスクロールすると、以前に作成されたビューを再利用してビューを表示しようとしますconvertView。次の行に注意してください。

        if (convertView == null) {
            // You create a view using the proper item
            btv = new AvailableExpenseView(context, expenses.get(position)); 
        } else {
            // You don't override the item that was previously assigned 
            // when the view was created
            btv = (AvailableExpenseView) convertView;
        }    

convertViewがnullの場合、新しいビューを作成していますが、アイテムを使用してビューを作成しています。したがって、これが位置0で呼び出されたとしましょう。リストの最初にある経費を使用してビューを作成します。後で、listViewは位置20のビューを取得する必要があり、「okは位置0に使用したビューを再利用できます」と言うので、このビューは次のように渡されますconvertViewが、このビューはすでに位置0のアイテムで作成されています。これをオーバーライドしません。したがって、20番目のアイテムを表す最初のアイテムを持つビューを使用することになります。

これを解決するには、次のようなことを簡単に行うことができます。

        AvailableExpenseView btv;

        if (convertView == null) {
            // dont create your view with an item
            btv = new AvailableExpenseView(context);
        } else {
            btv = (AvailableExpenseView) convertView;
        }

        // Assign the expense wether it is a newly created view or
        // a view that is reused
        btv.setExpense(expenses.get(position));

もちろん、ビューにデータを入力するためのメソッドを編集AvailableExpenseViewおよび作成する必要があります。setExpense()

于 2012-01-04T17:44:35.960 に答える
0

AvailableExpenseView新しいインスタンスの場合と同様に、リサイクルの場合はExpensesをexpenses.get(position)に設定する必要があります。

間違った行(インスタンス化された行であり、再利用している行ではない行)で間違った行を犠牲にして表示するインスタンスがリサイクルされる場合。

より正確に言うと、コードは提供しませんが、次のようになりますAvailableExpenseView

        public class AvailableExpenseView {

          private Expense expense = null; 

          public class AvailableExpenseView( Context context ) {
             super( context );
          }//cons

          /*
           Just add this method and use it.
          */

          public void setExpense( Expense expense ) {
            this.expense = expense;
          }//met
        }//class

次に、アダプタでこれを行います:

        if (convertView == null) {
            btv = new AvailableExpenseView(context);
        } 
        btv = (AvailableExpenseView) convertView;
        btv.setExpense( expenses.get( expenses.get(position) ) );

緩いコンストラクターを持つコンポーネントがあると便利です。ボタンを作成するために何も必要とされないJVM内の例について考えてみてください。その後、直交法(プロパティの「セッター」)を使用してカスタマイズできます。コンポーネントをこのように設計して、使いやすく、より多価にします。

于 2012-01-04T18:10:20.813 に答える
0

あなたの問題はここにあります:

if (convertView == null) {
  btv = new AvailableExpenseView(context, expenses.get(position));
} else {
  btv = (AvailableExpenseView) convertView;
} 

convertViewがnullの場合、Expenseが位置にある新しいAvailableExpenseViewを作成します。これで結構です。

ただし、convertViewがnullでない場合は、既存のAvailableExpenseViewを参照します。これは以前に(前の場合)現在の位置に表示したい経費とは異なる経費に初期化されています。

2つのオプションがあります:新しいAvailableExpenseViewを作成する場合でも、リサイクルする場合でも、正しいExpenseが使用されるように、このifブロックの後にbtvのExpenseを設定します-

または:elseブロックで、リサイクルされたビューの正しいExpenseオブジェクトを設定します。

于 2012-01-04T18:16:21.417 に答える