1. 程式人生 > >RecyclerView新增頭部(addHeaderView)和腳部(addFooterView)的封裝

RecyclerView新增頭部(addHeaderView)和腳部(addFooterView)的封裝

RecyclerView的功能強大之處就不用說了,但是相比於listview來說,它也有些小缺點,比如:沒有了間隔線divider,沒有addHeaderViewaddFooterView等方法,所以用起來不是那麼方便。今天主要完成RecyclerView的addHeaderView和addFooterView方法。
執行效果如下:

這裡寫圖片描述

第一步:自定義RecyclerView,程式碼如下:

public class XRecyclerView extends RecyclerView {

    //用來儲存新增的headerView和footerView
    private ArrayList<View> mHeadView = new
ArrayList<>(); private ArrayList<View> mFootView = new ArrayList<>(); //RecyclierView的介面卡 private Adapter mAdapter; public XRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } //新增頭部view,仿ListView的原始碼改造 public
void addHeaderView(View headerView) { mHeadView.add(headerView); if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) { mAdapter = new HeaderViewRecyclerAdapter(mHeadView,mFootView, mAdapter); } } } //新增腳View
public void addFooterView(View footView) { mFootView.add(footView); if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) { mAdapter = new HeaderViewRecyclerAdapter(mHeadView,mFootView, mAdapter); } } } @Override public void setAdapter(Adapter adapter) { //參考listview方法 setAdapter的原始碼,對adapter進行更換 if (mHeadView.size() > 0 || mFootView.size() > 0) mAdapter = new HeaderViewRecyclerAdapter(mHeadView, mFootView, adapter); else { mAdapter = adapter; } super.setAdapter(mAdapter); } }

第二步自定義RecyclerView的adapter,程式碼如下:

public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter {
    private final int HEADER = 1;
    private final int FOOTER = 2;
    private ArrayList<View> mHeadView;
    private ArrayList<View> mFootView;
    private RecyclerView.Adapter mAdapter;

    public HeaderViewRecyclerAdapter(ArrayList<View> HeadView, ArrayList<View> FootView, RecyclerView.Adapter adapter) {
        mAdapter = adapter;
        if (HeadView == null) {
            //為了防止空指標異常
            mHeadView = new ArrayList<>();
        } else {
            mHeadView = HeadView;
        }

        if (FootView == null) {
            mFootView = new ArrayList<>();
        } else {
            mFootView = FootView;
        }

    }


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //頭部修改newHeadViewHolder的方法,mFooterView,有幾個頭,就需要幾個headViewHolder
        if (viewType == HEADER) {
            return new HeadViewHolder(mHeadView.get(0));
        } else if (viewType == FOOTER) {
            //腳部,修改newHeadViewHolder的方法,mFooterView,有多個
            return new FootViewHolder(mFootView.get(0));
        }
        //body部分,暴露出去操作
        return mAdapter.onCreateViewHolder(parent, viewType);
    }

    //判斷view的型別,頭,身體,腳
    @Override
    public int getItemViewType(int position) {
        int headcount = getHeadCount();
        //返回頭部
        if (position < headcount) {
            //返回頭部型別,
            return HEADER;
        }

        //body型別
        final int midPosition = position - headcount;
        int itemCount = 0;
        if (mAdapter != null) {
            itemCount = mAdapter.getItemCount();
            if (midPosition < itemCount) {
                //返回type不要寫死了,body的型別可能不一致
                return mAdapter.getItemViewType(midPosition);
            }
        }

        //Footer型別
        return FOOTER;

    }


    /**
     * 和資料繫結,這裡只做body部分的繫結
     * 頭和腳的資料繫結邏輯都是在外部操作的
     * 傳入前都已經繫結好l
     */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int headcount = getHeadCount();
        if (position < headcount) {
            //頭部資料繫結,外部傳入前已經操作,這裡不再操作
            return;
        }

        //body資料繫結
        final int midPosition = position - headcount;
        int itemcount = 0;
        if (mAdapter != null) {
            itemcount = mAdapter.getItemCount();
            if (midPosition < itemcount) {
                //暴露出去自由操作,傳入的是調整後的位置,而不是算上頭角的位置
//                mAdapter.onBindViewHolder(holder, position);
                mAdapter.onBindViewHolder(holder, midPosition);
                return;
            }
        }
        //腳部資料繫結,和頭一樣,啥也不用操作

    }

    @Override
    public int getItemCount() {
        //身體部分不為空
        if (mAdapter != null) {
            return getHeadCount() + getFootCount() + mAdapter.getItemCount();
        } else {
            //只有頭和腳的情況下
            return getHeadCount() + getFootCount();
        }
    }


    private int getFootCount() {
        return mFootView.size();
    }

    public int getHeadCount() {
        return mHeadView.size();
    }

    /**
     * 面兩個head viewholder 沒什麼卵用
     * viewholder是為了相同的item減少findviewbyid的時間
     * 頭部holder和尾部holder沒有共性的findviewbyid
     * 為了拓展方便只得建立,但是不會用到
     */

    class HeadViewHolder extends RecyclerView.ViewHolder {

        public HeadViewHolder(View itemView) {
            super(itemView);
        }
    }

    class FootViewHolder extends RecyclerView.ViewHolder {

        public FootViewHolder(View itemView) {
            super(itemView);
        }
    }

}

第三步,就是在activity中使用剛才寫的recyclerview,程式碼如下:

public class MainActivity extends AppCompatActivity {

    private XRecyclerView recyclerView;
    private List<String> list = new ArrayList<>();

    private View headView;
    private View footView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = ((XRecyclerView) findViewById(R.id.recyclerView));
        initData();
        initHeaderView();
        recyclerView.addHeaderView(headView);

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

    }

    private void initHeaderView() {
        headView = LayoutInflater.from(this).inflate(R.layout.header, null);
        footView = LayoutInflater.from(this).inflate(R.layout.footer, null);
    }

    private void initData() {
        for (int i = 0; i < 10; i++) {
            list.add("我是身體body" + i);
        }
    }

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


        private List<String> list;

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

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View itemView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, parent, false);
            MyViewHolder holder = new MyViewHolder(itemView);
            return holder;
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.text.setText(list.get(position));
        }


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

        class MyViewHolder extends RecyclerView.ViewHolder {
            TextView text;

            public MyViewHolder(View itemView) {
                super(itemView);
                text = (TextView) itemView.findViewById(R.id.tv_item);
            }
        }
    }
}

總結:這種方法只能新增一個頭和一個腳,本來是想能任意新增頭和腳的,後來發現有點問題,

   if (viewType == HEADER) {
            return new HeadViewHolder(mHeadView.get(0));
        } else if (viewType == FOOTER) {
            //腳部,修改newHeadViewHolder的方法,mFooterView,有多個
            return new FootViewHolder(mFootView.get(0));
        }
        //body部分,暴露出去操作
        return mAdapter.onCreateViewHolder(parent, viewType);

在viewholder建立的時候,頭部和尾部也有viewholder,這個物件池不能複用,因為頭和腳可以是各種不同型別的***,一旦新增多個頭和腳的時候就有問題,這個問題待搞定。