web-dev-qa-db-ja.com

ArrayAdapter順のListViewは、スクロール時に混乱します

カスタムArrayAdapterにListViewがあり、各行にImageViewとTextViewのアイコンが表示されます。リストをスクロールできる長さにすると、順序は正しく始まりますが、下にスクロールし始めると、以前のエントリの一部が再表示され始めます。上にスクロールすると、古い順序が変わります。これを繰り返し行うと、最終的にはリスト全体の順序がランダムに見えるようになります。したがって、リストをスクロールすると、子の順序が変更されるか、図面が正しく更新されません。

このようなことが起こる原因は何ですか?アイテムがユーザーに表示される順序は、ArrayListに追加される順序と同じにするか、少なくとも1つの静的な順序のままにする必要があります。より詳細な情報を提供する必要がある場合は、お知らせください。どんな助けでもありがたいです。ありがとう。

43
Dan B

同様の問題がありましたが、カスタムリストの項目をクリックすると、画面上の項目が順番に逆になりました。もう一度クリックすると、元の状態に戻ります。

これを読んだ後、getViewメソッドをオーバーロードするコードを確認しました。私はConvertedViewからビューを取得していました。それがnullの場合は、そのときに自分で作成します。ただし、ブレークポイントを設定した後、クリックするたびにこのメソッドが呼び出され、その後のクリックで、convertedViewがnullでなかったため、項目が設定されていなかったことがわかりました。

これがその例です。


public View getView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;
    if (view == null)
    {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = vi.inflate(R.layout.listitemrow, null);

        RssItem rssItem = (RssItem) super.getItem(position);
        if (rssItem != null)
        {
            TextView title = (TextView) view.findViewById(R.id.rowtitle);
            if (title != null)
            {
                title.setText(rssItem.getTitle());
            }
        }
    }
    return view;
}

微妙な変更は、ビューのnullチェックの閉じ括弧を、膨張直後に移動しています。


public View getView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;
    if (view == null)
    {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = vi.inflate(R.layout.listitemrow, null);
    }
    RssItem rssItem = (RssItem) super.getItem(position);
    if (rssItem != null)
    {
        TextView title = (TextView) view.findViewById(R.id.rowtitle);
        if (title != null)
        {
            title.setText(rssItem.getTitle());
        }
    }
    return view;
}

これが同じ問題を経験している他の人に役立つことを願っています。

59
farcrats

以下のfarcatsの答えをより一般的な方法でさらに明確にするために、ここに私の説明があります:

vi.inflate操作(XMLから行のレイアウトを解析し、適切なViewオブジェクトを作成するためにここで必要)はif(view == null)ステートメントを効率化するため、同じオブジェクトが表示されるたびに何度も膨張することはありません。

ただし、getViewメソッドの他の部分は他のパラメーターを設定するために使用されるため、if(view == null)ステートメントに含めないでください。

同様に、このメソッドの他の一般的な実装では、findViewByIdを使用して、一部のtextView、ImageView、またはImageButton要素にlist [position]の値を入力する必要があります。その後は。setTextまたは。setImageBitmap操作です。これらの操作は、bothインフレによって最初からビューを作成した後に行う必要がありますnullでない場合は、既存のビューを取得します。

このソリューションがBaseAdapterに適用されるもう1つの良い例が BaseAdapterにより、スクロール時にListViewの順序が狂う に表示されます。

4
wiztrail

ListViewは、スクロール時にビューオブジェクトを再利用します。 getViewメソッドをオーバーライドしていますか?すべてのビューに各プロパティを設定する必要があります。以前に持っていたものを記憶しているとは限りません。その方法を投稿すると、誰かが間違っている部分を指摘する可能性があります。

3
Cheryl Simon

ListView、AdapterView、およびEditTextと3つのスピナーを含むビュー(search_options)があります。 ListViewアイテムは、(search_options)レイアウトの複数のコピーであり、ユーザーはListViewにオプションを追加し、[検索]をクリックして、ユーザーオプションに従って作成されたSQLクエリを送信できます。

ConvertViewの混合が不適切であることがわかったので、アクティビティにグローバルリスト(myViews)を追加し、それをArrayAdapterに渡しました。次に、ArrayAdapter(getView)で、新しく追加されたすべてのビュー(myViews)を追加します。

また、getViewで、convertViewがnullかどうかをチェックする代わりに、グローバルリスト(myViews)に選択した(位置)のビューがあるかどうかをチェックします。

1-アクティビティにこれを追加:

Map<Integer, View> myViews = new HashMap<>();

次に、アダプターコンストラクターを使用してそれをArrayAdapterに渡します。

mSOAdapter = new SearchOptionsAdapter(getActivity(), resultStrs, myViews);

2- getViewの場合:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View view;
    ViewHolder viewHolder;

    if (!myViews.containsKey(position)) {
        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        view = inflater.inflate(R.layout.search_options, parent, false);

        /// ...... YOUR CODE

        myViews.put(position, view);

        FontUtils.setCustomFontsIn(view, getContext().getAssets());

    }else {
        view = myViews.get(position);
    }

    return view;
}

最後に、これ以上混合アイテムはありません...

0
Ibrahim