RecyclerView添加头脚布局,使用SwipeRefreshLayout的实现

上篇文章记录了将viewpager抽取出来,那么这篇文章我们继续来实现,将viewpager做为头布局添加给RecyclerView。这使用到了一种设计模式 - 包装类设计模式,大家可以先了解下这个模式更有利于理解,我也会把本篇实现的思路给出个思维导图的。
看下效果图吧:

首先来个bean对象,等下封装数据使用:

public class Item {

    private String maintitle;
    private String subtitle;

    public Item(String maintitle, String subtitle){
        this.maintitle = maintitle;
        this.subtitle = subtitle;
    }

    public String getMaintitle() {
        return maintitle;
    }

    public String getSubtitle() {
        return subtitle;
    }
}

然后我们创建一个类WrapRecyclerView继承自RecyclerView:

// 将recycle进行封装
public class WrapRecyclerView extends RecyclerView {

    private ArrayList mHeadViewList = new ArrayList();
    private ArrayList mFootViewList = new ArrayList();
    private Adapter mAdapter;

    public WrapRecyclerView(Context context) {
        super(context);
    }

    public WrapRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public WrapRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void addHeaderView(View view){
        mHeadViewList.clear();
        mHeadViewList.add(view);
        if (mAdapter != null){
            if (!(mAdapter instanceof RecylerWrapAdapter)){
                mAdapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,mAdapter);
            }
        }
    }

    public void addFootView(View view){
        mFootViewList.clear();
        mFootViewList.add(view);
        if (mAdapter != null){
            if (!(mAdapter instanceof RecylerWrapAdapter)){
                mAdapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,mAdapter);
            }
        }
    }

    @Override
    public void setAdapter(Adapter adapter) {
        if (mHeadViewList.isEmpty() && mFootViewList.isEmpty()){
            super.setAdapter(adapter);
        }else{
            adapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,adapter);
            super.setAdapter(adapter);
        }
        mAdapter = adapter;
    }
}
//在布局使用,使用系统的SwipeRefreshLayout包裹下
.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/srl_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <com.wb.head.widget.WrapRecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    .support.v4.widget.SwipeRefreshLayout>
//然后在MainActivity的onCreate中获取实例,进行初始化。还是我们上篇的那个MainActivity
 recycler = (WrapRecyclerView) findViewById(R.id.recycler);
 refresh = (SwipeRefreshLayout) findViewById(R.id.srl_refresh);
 initRecycler();
 initRefresh();
private void initRecycler(){
        ll_headparent.removeView(rl_head);
        recycler.addHeaderView(rl_head);

        TextView textView = new TextView(this);
        textView.setText("我是脚布局");
        textView.setBackgroundColor(getResources().getColor(R.color.colorAccent));
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,50);
        textView.setGravity(Gravity.CENTER);
        textView.setLayoutParams(params);
        recycler.addFootView(textView);

        mRecylerAdpater = new RecylerAdpater(loadData(0,6));
        recycler.setAdapter(mRecylerAdpater);
        recycler.setLayoutManager(new LinearLayoutManager(this));
        recycler.setHasFixedSize(true);
        onRecyclerClick();
    }
// 如果连续快速点击,条目的动画会有一个bug,所以使用了一个标记来禁止点击连续点击
boolean isClick = false;
    private void onRecyclerClick(){
        mRecylerAdpater.setOnItemClickLitener(new RecylerAdpater.OnItemClickLitener() {
            @Override
            public void onItemClick(View view, int position) {
                if (!isClick){
                    isClick = true;
                    Toast.makeText(MainActivity.this, "点了我position" + position, Toast.LENGTH_SHORT).show();
                    ViewCompat.animate(view).setDuration(200).scaleX(0.9f).scaleY(0.9f).setInterpolator(new CycleInterpolator())
                            .setListener(new ViewPropertyAnimatorListener() {

                                @Override
                                public void onAnimationStart(View view) {}

                                @Override
                                public void onAnimationEnd(View view) {
                                    isClick = false;
                                }

                                @Override
                                public void onAnimationCancel(View view) {}
                            }).withLayer().start();
                }
            }
            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(MainActivity.this, "长按了我position" + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private class CycleInterpolator implements android.view.animation.Interpolator {

        private final float mCycles = 0.5f;

        @Override
        public float getInterpolation(final float input) {
            return (float) Math.sin(2.0f * mCycles * Math.PI * input);
        }
    }

ArrayList items = new ArrayList();
private ArrayList loadData(int start,int end){
    items.clear();
    for (int i = start; i < end; i++) {
        items.add(new Item("Item title :" + i,"This is the Item number :" + i));
    }
    return items;
}
// 模仿访问网络,进行刷新数据
private void initRefresh(){
        refresh.setColorSchemeResources(android.R.color.holo_blue_light,
                android.R.color.holo_red_light,android.R.color.holo_orange_light,
                android.R.color.holo_green_light);
        refresh.setProgressBackgroundColorSchemeColor(getResources().getColor(android.R.color.white));
        refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        items.clear();
                        mRecylerAdpater = new RecylerAdpater(loadData(10, 16));
                        recycler.setAdapter(mRecylerAdpater);
                        mRecylerAdpater.notifyDataSetChanged();
                        onRecyclerClick();
                        refresh.setRefreshing(false);
                    }
                }, 4000);
            }
        });
    }

然后我们在创建个类RecylerWrapAdapter继承自RecyclerView.Adapter对adapter进行包装:

public class RecylerWrapAdapter extends RecyclerView.Adapter{

    private RecyclerView.Adapter mAdapter;
    private ArrayList mHeaderViews;
    private ArrayList mFootViews;
    private final ArrayList EMPTY_INFO_LIST = new ArrayList();
    private int mCurrentPosition;

    public RecylerWrapAdapter(ArrayList mHeaderViews,ArrayList mFootViews,RecyclerView.Adapter mAdapter){
        this.mAdapter = mAdapter;
        if (mHeaderViews == null){
            this.mHeaderViews = EMPTY_INFO_LIST;
        }else{
            this.mHeaderViews = mHeaderViews;
        }

        if (mFootViews == null){
            this.mFootViews = EMPTY_INFO_LIST;
        }else{
            this.mFootViews = mFootViews;
        }
    }

    public int getHeaderCount(){
        return mHeaderViews.size();
    }

    public int getFootCount(){
        return mFootViews.size();
    }

    /**
     * 返回该position对应的item的id
     * @param position
     * @return
     */
    @Override
    public long getItemId(int position) {
        int heads = getHeaderCount();
        if (mAdapter != null && position >= heads){
            int adjposition = position - heads; //减去头布局的当前位置
            int adapterCount = mAdapter.getItemCount(); //总共有多少条目
            if (adjposition < adapterCount){ // 当前位置如果是在条目中的
                return mAdapter.getItemId(adjposition);
            }
        }
        return -1;
    }

    @Override
    public int getItemCount() {
        if (mAdapter != null){
            return getHeaderCount() + getFootCount() + mAdapter.getItemCount();
        }else{
            return getHeaderCount() +getFootCount();
        }
    }

    /**
     * 判断应该返回的是头布局还是正常子布局还是脚布局 在onCreateViewHolder中使用
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        mCurrentPosition = position;
        int heads = getHeaderCount();
        // 也就是说recycle的第一个条目位置为头布局
        if (position < heads){
            // 返回类型为头布局
            return RecyclerView.INVALID_TYPE;
        }
        int adjposition = position - heads; //减去头布局后当前布局的位置
        int adapterCount = 0;
        if (mAdapter != null){
            adapterCount = mAdapter.getItemCount();
            if (adjposition < adapterCount){
                //返回类型为正常布局
                return mAdapter.getItemViewType(adjposition);
            }
        }
        // 返回类型为脚布局
        return RecyclerView.INVALID_TYPE - 1;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == RecyclerView.INVALID_TYPE){
            // 返回头布局
            return new HeaderViewHolder(mHeaderViews.get(0));
        }else if (viewType == RecyclerView.INVALID_TYPE - 1){
            // 返回脚布局
            return new HeaderViewHolder(mFootViews.get(0));
        }
        // 返回正常布局
        return mAdapter.onCreateViewHolder(parent,viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int heads = getHeaderCount();
        if (position < heads) return;
        int adjPosition = position - heads;
        int adapterCount = 0;
        if (mAdapter != null){
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount){
                // 绑定正常条目数据
                mAdapter.onBindViewHolder(holder,adjPosition);
                return;
            }
        }
    }

    private class HeaderViewHolder extends RecyclerView.ViewHolder{

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

现在包装类写完了,但我们的RecyclerView还没有Adapter的,那我们就创建吧,和使用普通RecyclerView的Adapter一样:

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

    private List items;

    public RecylerAdpater(List list){
        super();
        items = list;
    }

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

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

    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        Item item = (Item)items.get(position);
        holder.mTitle.setText(item.getMaintitle());
        holder.mSubtitle.setText(item.getSubtitle());

        if (mOnItemClickLitener != null){
            // 设置点击事件  通过系统view类的回调设置我们的回调
            holder.ll_item.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.ll_item,pos);
                }
            });

            // 设置长按事件 通过系统view类的回调设置我们的回调
            holder.ll_item.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.ll_item,pos);
                    return true;
                }
            });
        }
    }

    class MyViewHolder extends RecyclerView.ViewHolder{

        TextView mTitle;
        TextView mSubtitle;
        LinearLayout ll_item;

        public MyViewHolder(View itemView) {
            super(itemView);
            mTitle = (TextView) itemView.findViewById(R.id.maintitle);
            mSubtitle = (TextView) itemView.findViewById(R.id.subtitle);
            ll_item = (LinearLayout) itemView.findViewById(R.id.ll_item);
        }
    }

    //回调接口用于点击事件
    public interface OnItemClickLitener{
        void onItemClick(View view,int position);
        void onItemLongClick(View view,int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener){
        this.mOnItemClickLitener = mOnItemClickLitener;
    }
}

OK,现在大功告成,我们已经在MainActivity的initRecycler()方法中使用了,运行就可以看到效果了。
对包装类设计模式不熟悉的朋友可能会有些疑问,下面给大家贴出我做的思维导图:
RecyclerView添加头脚布局,使用SwipeRefreshLayout的实现_第1张图片
最好的方法还是自己写出来,断点下就清楚这个设计模式和执行流程了。如有哪里不足,欢迎指教。

Reference:
http://www.it165.net/pro/html/201507/48065.html
http://blog.csdn.net/lmj623565791/article/details/45059587
https://github.com/DevLight-Mobile-Agency/NavigationTabBar

项目代码已经发布到github,地址:https://github.com/viewpager/HeadApplication

你可能感兴趣的:(android学习笔记)