ソース解析-ListViewコンポーネントaddHeaderView()メソッドのソース解析


ぶんせきりょく


最近、自分のプロジェクトを書いて、RecyclerViewというコントロールを使って、私が以前よく使っていたListViewの代わりにしました.もちろん以前のListViewよりも機能が強すぎる気がします.しかし、現在のRecyclerViewには、addHeadView()とaddFooterView()の2つのリストコンポーネントでよく使用される機能が追加されていません.ネット上には、RecyclerViewにこの2つの機能を追加する方法を紹介するブログがたくさんあります.主にonCreateViewHolderonBindViewHolderで文章を作っています.追求のあるAndroid開発者として直接彼らを写すことはできません.自分の考えもいくつか書きます.だから私はListViewのソースコードに戻ってGoogleがどのようにこの機能を実現したのかを見ました

addHeadView()ソース分析


ソースエントリ


2つのaddリロード方法は最後にここに来て、まず英語の注釈を見ます
/** * Add a fixed view to appear at the top of the list. If this method is * called more than once, the views will appear in the order they were * added. Views added using this call can take focus if they want. * <p> * Note: When first introduced, this method could only be called before * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be * called at any time. If the ListView's adapter does not extend * {@link HeaderViewListAdapter}, it will be wrapped with a supporting * instance of {@link WrapperListAdapter}. * * @param v The view to add. * @param data Data to associate with this view * @param isSelectable whether the item is selectable */
    public void addHeaderView(View v, Object data, boolean isSelectable) {}

まず方法の注釈部分を見て、英語の大まかな意味は:これはadapterにトップレベルのビューを追加する方法で、使用ヒントとパラメータの説明があります.
ListViewは、MVCモードモデル(model)−ビュー(view)−コントローラ(controller)ListView担当UIを用いて、ViewレイヤがAdapterを構築したときに入力されたDataデータがModelレイヤであり、データのソースであることを示す.Adapterアダプタは、ViewレイヤがどのようなUIを表示する必要があるかを制御し、最も重要なControllerレイヤです.
だからListViewにheadを追加するのは、実はadapterで修正することです.note:この方法は、バインドアダプタsetAdapter()の前に呼び出されることを示す.

ソースコード


中のソースコードを見てみると、コードは多くありません.主に3段階に分けて操作する
 public void addHeaderView(View v, Object data, boolean isSelectable) {
         //     list 
        final FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
        mHeaderViewInfos.add(info);
        mAreAllItemsSelectable &= isSelectable;

        // Wrap the adapter if it wasn't already wrapped.
        if (mAdapter != null) {
            //   
            // mAdapter HeaderViewListAdapter   head、foot adapter  
            //   HeaderViewListAdapter 
            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();
            }
        }
    }

FixedViewInfoクラス


HeadViewビューのパッケージで、3つのフィールドがパッケージされています.
 /** * A class that represents a fixed view in a list, for example a header at the top * or a footer at the bottom. */
    public class FixedViewInfo {
        /** The view to add to the list */
        public View view;
        /** The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. */
        public Object data;
        /** <code>true</code> if the fixed view should be selectable in the list */
        public boolean isSelectable;
    }

HeaderView ListAdapterのソースコード分析


内部オブジェクト


クラスには3つのキー内部オブジェクトが保存されています
public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {
    // --> 
    private final ListAdapter mAdapter;

    // These two ArrayList are assumed to NOT be null.
    // They are indeed created when declared in ListView and then shared.
    ArrayList<ListView.FixedViewInfo> mHeaderViewInfos;
    ArrayList<ListView.FixedViewInfo> mFooterViewInfos;
    // --> 
    // Used as a placeholder in case the provided info views are indeed null.
    // Currently only used by some CTS tests, which may be removed.
    //  ArrayList<ListView.FixedViewInfo>     
    static final ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST =
        new ArrayList<ListView.FixedViewInfo>();

    boolean mAreAllFixedViewsSelectable;

    private final boolean mIsFilterable;

コンストラクタ


初期化と付与を担当する3つのパラメータの構造関数
public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
                                 ArrayList<ListView.FixedViewInfo> footerViewInfos,
                                 ListAdapter adapter) {
        mAdapter = adapter;
        mIsFilterable = adapter instanceof Filterable;

        if (headerViewInfos == null) {
        // null    new   
            mHeaderViewInfos = EMPTY_INFO_LIST;
        } else {
            mHeaderViewInfos = headerViewInfos;
        }

        if (footerViewInfos == null) {
            mFooterViewInfos = EMPTY_INFO_LIST;
        } else {
            mFooterViewInfos = footerViewInfos;
        }

        mAreAllFixedViewsSelectable =
                areAllListInfosSelectable(mHeaderViewInfos)
                && areAllListInfosSelectable(mFooterViewInfos);
    }

headとfootビューのキーの追加


getViewで変更する
public View getView(int position, View convertView, ViewGroup parent) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        // position 0 view  FixedViewInfo View 
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).view;
        }

        // itemView   mAdapter getView()   BaseAdapter.getView(), , 
        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getView(adjPosition, convertView, parent);
            }
        }
        //foot Head 
        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).view;
    }

その他の方法


一般的なadapterとはあまり違いはなく、私たちの分析点ではありません.

まとめ

  • このステップのソースコード解析から,ListViewのaddHeadView()は,実はadapterのgetView()を修正する方法であることが分かる.使用時にHeaderViewListAdapterクラスをパッケージするにはheadとfootを専門に処理する方法があります.この考え方はネット上の多くのブログとあまり差がないので、皆さんはソースコードから考えを見つけているのではないでしょうか.
  • ListViewソースコードから得られた考え方は、実はRecyclerViewにも応用でき、Google公式は提供していないので自分で手を出すことができます.もちろんRecyclerViewはListViewよりも複雑でMVCのC層でRecyclerViewを分離する.AdapterとRecyclerView.LayoutManagerは、Viewの表示内容とレイアウト位置をそれぞれ制御します.上の分析で得られた考え方を次にaddHeadViewとaddFootViewのRecyclerViewを書きます.
  • ここではRecyclerViewにaddHeadViewを用いた解析整理
  • がある