1. ホーム
  2. Android

Android ListViewでaddHeaderを使用する

2022-02-17 15:40:14
<パス

あるアプリ

レイアウトが非常に似ています。上が検索バー、下がローテーション、カテゴリー、アクティブテーマ、おすすめ商品リスト、そして下のバーです。全部をScrollViewで実装すれば簡単ですが、下のおすすめ商品は数が不定で、結構な数になる可能性があるので
1. 商品リストにListViewを使用する場合、ScrollViewとの衝突とListViewの高さの問題を解決する必要があります。
2.ScrollViewやLinearLayoutを使った商品リストでは、画像の枚数が多い場合、キャッシュの再利用ができないため、パフォーマンスの問題が発生する場合があります。


addHeader,addFooterメソッドの使い方は非常に簡単なので、ここでは説明しません。主なポイントは、それらを使用する際の潜在的な落とし穴を文書化することです。

1. ヘッダーの表示・非表示について

ListViewには共通のHeader関連APIがあります

listView.getHeaderViewsCount();


listView.addHeaderView(View v);


listView.removeHeaderView(View v);


listView.areHeaderDividersEnabled();

4つの関数で、順番やHeaderを表示するかどうかを制御するAPIはない。
ヘッダーを隠すには?表示されなくなったヘッダーは emoveHeaderView 再び表示する必要がある場合はどうすればよいのでしょうか。順序の問題があります。
そして、headerViewに設定することを考え GONE これは理論的には正しいのですが、実際には何の効果もなく、空白のプレースホルダーが残り、その親が正しいレスポンスとレイアウトになることを意味します。一般的な解決策は、headerViewを隠したい場合、送信されたchildViewのvisibilityを GONE 表示時には、Viewの可視性を VISIBLE .
最終的な解答は
addHeaderViewを使用して、すべてのHeaderViewをListViewに順番に追加することから始め、HeaderViewの子ビューの可視性を制御することによって、それらが表示されるかどうかを制御します。

2. setAdapterとaddHeaderViewの実行順序について

ListViewがヘッドビューを追加したい場合、その処理は addHeaderView メソッドを呼び出し、ListViewにデータを設定したい場合は setAdapter メソッドを使用します。ただし、下位バージョンのデバイス(API<=17)では IllegalStateException: Cannot add header view to list -- setAdapter has already been called. これは、HeaderViewをリストに追加しているためです。これは setAdapter .
ソースコードに目を通すと
API-17 (Android 4.2)

public void addHeaderView(View v, Object data, boolean isSelectable) {

        if (mAdapter ! = null && ! (mAdapter instanceof HeaderViewListAdapter)) {
            throw new IllegalStateException(
                    "Cannot add header view to list -- setAdapter has already been called.");
        }

        FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
        mHeaderViewInfos.add(info);

        // in the case of re-adding a header view, or adding one later on,
        // we need to notify the observer
        if (mAdapter ! = null && mDataSetObserver ! = null) {
            mDataSetObserver.onChanged();
        }
}

API-18 (Android 4.3)

public void addHeaderView(View v, Object data, boolean isSelectable) {
        final FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
        mHeaderViewInfos.add(info);

        // Wrap the adapter if it wasn't already wrapped.
        if (mAdapter ! = null) { if (!
            if (! (mAdapter instanceof HeaderViewListAdapter)) {
                mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }

            // In the case of re-adding a header view, or adding one later on,
            // we need to notify the observer.
            if (mDataSetObserver ! = null) {
                mDataSetObserver.onChanged();
            }
        }
}

API<=17では、アダプターが空でなければ直接例外を投げるのに対し、API>17ではmAdapterを判定し、空であればまずmHeaderViewInfosにヘッダーを記録し、HeaderViewListAdapterの場合はsetAdapterでヘッダーとアダプターをカプセル化して、空でなければ直接HeaderViewListAdapterを構築することがわかると思います。
したがって、互換性の問題を確実にするために、settingAdapterの前にListViewにすべてのヘッダーを追加します。settingAdapterの後にHeaderViewを追加しないでください。

3. onItemClickListenにおける位置の問題

ListViewにHeaderやFooterがある場合、ListViewは内部でHeaderViewListAdapterをカプセル化することがソースコードからわかっているので、Headerを含むアイテムの位置はonItemClickListenの中で取得され、すでに我々の一般常識ではデータソースの位置ではありません。そのため、実際には Clicked position=fetched position-headerConunt もちろんこの方法で直接変換することもできますが、実際には HeaderViewListAdapter の内部で行ってくれています。
HeaderViewListAdapter.java

public Object getItem(int position) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (positions < numHeaders) {
            return mHeaderViewInfos.get(positions).data;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter ! = null) {
            adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItem(adjPosition);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).data;
    }


HeaderViewListAdapter の getItem() HeaderViewListAdapterのadjPositionは、実データソースChinaの位置となります。
そのため、onItemClickListenでデータを取得する場合は、以下のようにします。 parent.getAdapter().getItem(position); を使用して実体を取得します。(カスタムアダプタは getItem() メソッドを実行し、NULLを返さないようにします)。

のソースになります。 http://www.zhangningning.com.cn/blog/Android/Android_listview_addheade.html