RecyclerView——添加頭部和尾部

ListView中有個addHeaderView方法和addFooterView方法,因此觀看了ListView的實現原理之後,發現其實也沒那麼難,下面我們來看看ListView裏面addHeader的流程

該方法首先判斷傳進來的headerView是否在RecyclerView裏面的子控件,若不是則拋一個警告,ListView裏面有一個mHeaderViewInfos和mFooterViewInfos用於保存HeaderView和FooterView的信息,當添加一個HeaderView時,就會添加到mHeaderViewInfos中


下面的方法把我們傳進來的Adapter替換成了一個WraperListAdapter,也就是偷樑換柱啦



貼不上圖了,上代碼吧。。。

//以上只是將要添加的HeaderView一個列表中並跟Adapter一起被封裝成HeaderViewListAdapter,並沒有說在哪裏顯示,因此猜測HeaderViewListAdapter應該會有顯示View的方法,因此我想這在ListView的setAdapter中會不會找到線索
@Override
public void setAdapter(ListAdapter adapter) {
	//先是確保當前的Adapter是爲空的
    if (mAdapter != null && mDataSetObserver != null) {
        mAdapter.unregisterDataSetObserver(mDataSetObserver);
    }

    resetList();//清空ListView中原來的數據
    mRecycler.clear();//不知道mRecycler是個什麼鬼

    if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {//HeaderViweInfos或者mFooterViewInfos是否大於0
    	//若mHeaderViewInfos是大於0的,將Adapter封裝成HeaderViewListAdapter
        mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
    } else {//否則不做任何改變
        mAdapter = adapter;
    }

    mOldSelectedPosition = INVALID_POSITION;//目測是當前被選中的條目,將要進行綁定和顯示的,知道有這個東西就行了,其實我也不太懂
    mOldSelectedRowId = INVALID_ROW_ID;

    // AbsListView#setAdapter will update choice mode states.
    super.setAdapter(adapter);

    if (mAdapter != null) {
    	//下面其實就是調用的我們傳進來的Adapter的方法,setAdapter其實就是將我們傳進來的Adapter做了一層封裝
        mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
        mOldItemCount = mItemCount;
        mItemCount = mAdapter.getCount();
        checkFocus();

        mDataSetObserver = new AdapterDataSetObserver();//創建一個觀察者,用於觀察adapter中的數據是否發生變化
        mAdapter.registerDataSetObserver(mDataSetObserver);

        mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());//這個方法等會研究

        int position;
        if (mStackFromBottom) {//獲取要顯示的條目的position,每顯示一條,條目的數量就會減一
            position = lookForSelectablePosition(mItemCount - 1, false);
        } else {
            position = lookForSelectablePosition(0, true);
        }
        setSelectedPositionInt(position);
        setNextSelectedPositionInt(position);

        if (mItemCount == 0) {
        	//當條目的數量爲0時就是沒有數據要顯示啦
            checkSelectionChanged();
        }
    } else {//Adapter中沒有數據,就沒有東西顯示啦
        mAreAllItemsSelectable = true;
        checkFocus();
        checkSelectionChanged();
    }

    requestLayout();
}

所以實質上ListView調用addHeaderView()時只是對我們傳進去的Adapter動了手腳,將HeaderView和FooterView添加進去,把它封裝成了HeaderViewListAdapter,然而我們並不知情(這纔是封裝),裏面實際上調用的還是我們的Adapter的方法,所以若是我們想在RecyclerView上實現相同的效果,可以自定義一個HeaderViewListAdapter類,至於顯示應該是怎麼顯示Adapter就怎麼顯示HeaderViewListAdapter,這裏就先不研究啦


接下來實現爲RecyclerView添加一個頭部和尾部

按照ListView的流程來的話,先定義一個代理的Adapter類,畢竟實際的添加操作是在該類中完成的

package com.example.lsn5_materialdesign_wraprecyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;

public class MyHeaderViewListAdapter extends RecyclerView.Adapter {
    private RecyclerView.Adapter mAdapter;
    private ArrayList<View> mHeaderViewInfo;
    private ArrayList<View> mFooterViewInfo;

    //構造方法,有三個成員變量,一個是我們自己創建的Adapter,一個是HeaderViewInfo保存頭部的view,一個是mFooterViewInfo保存
    //尾部的view
    public MyHeaderViewListAdapter(ArrayList<View> headerViewInfo, ArrayList<View> footerViewInfo, RecyclerView.Adapter adapter){
        mAdapter = adapter;

        //如果沒有頭部和尾部,則將它們初始化爲空
        if(headerViewInfo == null){
            mHeaderViewInfo = new ArrayList<View>();
        }else{
            mHeaderViewInfo = headerViewInfo;
        }

        if(footerViewInfo == null){
            mFooterViewInfo = new ArrayList<View>();
        }else{
            mFooterViewInfo = footerViewInfo;
        }
    }

    //該類也是繼承了RecyclerView.Adapter類,因此也要重寫裏面的方法
    @Override
    public int getItemCount() {
        //當mAdapter不爲空,返回的長度爲頭部的長度,尾部的長度,mAdapter裏面數據的數目之和
        if(mAdapter != null){
            return getFooterViewCount() + mAdapter.getItemCount() + getHeaderViewCount();
        }else{
            return getFooterViewCount() + getHeaderViewCount();
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder vh, int position){
        //若是頭部或尾部則直接返回,在onCreateViewHolder時會返回一個mHeaderViewInfo中保存的View
        int numHeaders = getHeaderViewCount();
        if(position < numHeaders){
            return;
        }
        final int adjPosition = position - numHeaders;
        int adapterCounter = 0;
        if(mAdapter != null){
            adapterCounter = mAdapter.getItemCount();
            if(adjPosition < adapterCounter){
                mAdapter.onBindViewHolder(vh, adjPosition);
                return;
            }
        }
        //footer
    }

    private int getHeaderViewCount() {
        return mHeaderViewInfo.size();
    }

    private int getFooterViewCount() {
        return mFooterViewInfo.size();
    }

    //獲取RecyclerView裏麪條目的類型,這裏爲了識別header和footer,分別爲header和Footer設置了不同的返回值
    @Override
    public int getItemViewType(int position){
        int numHeaders = mHeaderViewInfo.size();
        //爲HeaderView是返回RecyclerView.INVALID_TYPE
        if(position < numHeaders){
            return RecyclerView.INVALID_TYPE;
        }

        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if(mAdapter != null){
            adapterCount = mAdapter.getItemCount();
            if(adjPosition < adapterCount){
                return mAdapter.getItemViewType(adjPosition);
            }
        }

        //footer返回RecyclerView.INVALID_TYPE - 1
        return RecyclerView.INVALID_TYPE - 1;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
        //header
        if(viewType == RecyclerView.INVALID_TYPE){
            return new HeaderViewHolder(mHeaderViewInfo.get(0));
        }else if(viewType == RecyclerView.INVALID_TYPE - 1) {//footer
            return new HeaderViewHolder(mFooterViewInfo.get(0));
        }
        return mAdapter.onCreateViewHolder(parent, viewType);
    }

    private class HeaderViewHolder extends RecyclerView.ViewHolder{
        public HeaderViewHolder(View view){
            super(view);
        }
    }

}


原生的RecyclerView中是沒有addHeaderView和addFooterView的,因此我們需要自己封裝一個RecyclerView

package com.example.lsn5_materialdesign_wraprecyclerview;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;

public class MyWrapRecyclerView extends RecyclerView {
    private ArrayList<View> mHeaderViewInfos = new ArrayList<>();
    private ArrayList<View> mFooterViewInfos = new ArrayList<>();
    private Adapter mAdapter;


    public MyWrapRecyclerView(Context context, AttributeSet attr) {
        super(context, attr);
    }

    public void addHeaderView(View v){
        mHeaderViewInfos.add(v);

        if(mAdapter != null){
            if(!(mAdapter instanceof MyHeaderViewListAdapter)){
                mAdapter = new MyHeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }
        }
    }

    public void addFooterView(View v){
        mFooterViewInfos.add(v);

        if(mAdapter != null){
            if(!(mAdapter instanceof MyHeaderViewListAdapter)){
                mAdapter = new MyHeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }
        }
    }

    @Override
    public void setAdapter(Adapter adapter){
        if(mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0){
            //在這裏遇到了一個小坑,大概是我腦子不好使了,先前一直傳入的是mAdapter,搞得List裏面的條目一直顯示不出來,調試才發現的。
            //調試程序很重要,不知道的到百度上搜,只要會很簡單的幾個步驟就行了
             mAdapter = new MyHeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        }else{
            mAdapter = adapter;
        }
        super.setAdapter(mAdapter);
    }
}


好吧,還有封裝一個Adapter,RecyclerView功能強大,但是用起來真麻煩

package com.example.lsn5_materialdesign_wraprecyclerview;

import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private List<String> list;

    public MyAdapter(List<String> list){
        this.list = list;
    }

    class MyViewHolder extends RecyclerView.ViewHolder{
        public TextView tv;

        public MyViewHolder(View view){
            super(view);
            this.tv = (TextView) view.findViewById(R.id.tv);
        }
    }

    @Override
    public int getItemCount(){
        return list.size();
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position){
        Log.d("zhou", "position : "+list.get(position));
        holder.tv.setText(list.get(position));
    }


    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.listitem, parent, false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

}
package com.example.lsn5_materialdesign_wraprecyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyWrapRecyclerView recyclerView = (MyWrapRecyclerView) findViewById(R.id.recyclerView);

        //創建一個TextView作爲HeaderView
        TextView headerView = new TextView(this);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        headerView.setLayoutParams(params);
        headerView.setText("我是HeaderView");
        recyclerView.addHeaderView(headerView);

        //創建一個TextView作爲FooterView
        TextView footerView = new TextView(this);
        params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        footerView.setLayoutParams(params);
        footerView.setText("我是FooterView");
        recyclerView.addFooterView(footerView);

        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 30; i++) {
            list.add("item "+i);
        }

        adapter = new MyAdapter(list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
    }
}

運行結果如下:




就到這了,困死我了,睡覺去
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章