装饰设计模式——RecyclerView添加头部和底部

装饰设计模式也称为包装设计模式,用来动态的扩展对象的功能,也是继承关系的一种替代方案之一,也就是说在不是用继承的方式下,采用装饰设计模式可以扩展一个对象的功能,可以是一个对象变得越来越强大。源码中就有很多地方用到了装饰设计模式,IO流、ContextCompat、ListView等,ListView的添加头部和底部就是采用装饰设计模式来实现的,而RecyclerView没有添加头部和底部,其实ListView也只不过是系统给实现了而已,既然这样可以参考ListView添加头部和底部的方式来给RecyclerView添加头部和底部。先写一个普通的RecyclerView列表效果,在这效果上面进行添加;

class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {

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

        @Override
        public void onBindViewHolder(ViewHolder holder, final int position) {
            holder.tvItem.setText(list.get(position));
            holder.tvItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this,"点击了"+position,Toast.LENGTH_LONG).show();
                }
            });
        }

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

        class ViewHolder extends RecyclerView.ViewHolder {
            public TextView tvItem;
            public ViewHolder(View itemView) {
                super(itemView);
                tvItem= (TextView) itemView.findViewById(R.id.tv_item);
            }
        }
    }

这个就是最常见的RecyclerView的adapter,接着定义一个adapter继承自RecyclerView.Adapter 并通过该构造方法传入一个adapter;

/**
 * Created by Administrator on 2019/1/12.
 * RecyclerView adapter 添加头部和底部
 */

public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private RecyclerView.Adapter mAdapter;
    //存储头部
    private ArrayList<View> mHeaderView;
    //存储底部
    private ArrayList<View> mFooterView;

    public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
        this.mAdapter = adapter;
        mHeaderView = new ArrayList<>();
        mFooterView = new ArrayList<>();
        this.mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver()         {
            @Override
            public void onChanged() {
                super.onChanged();
                //更新数据
                notifyDataSetChanged();
            }
        });
    }
}

在WrapRecyclerAdapter中新增添加头部/删除头部、添加底部/删除底部的方法;

/**
     * 添加头部
     *
     * @param view
     */
    public void addHeaderView(View view) {
        if (!mHeaderView.contains(view)) {
            mHeaderView.add(view);
            notifyDataSetChanged();
        }
    }

    /**
     * 添加底部
     *
     * @param view
     */
    public void addFooterView(View view) {
        if (!mFooterView.contains(view)) {
            mFooterView.add(view);
            notifyDataSetChanged();
        }
    }

    /**
     * 移除头部
     *
     * @param view
     */
    public void removeHeaderView(View view) {
        if (mHeaderView.contains(view)) {
            mHeaderView.remove(view);
            notifyDataSetChanged();
        }
    }

    /**
     * 移除底部
     *
     * @param view
     */
    public void removeFooterView(View view) {
        if (mFooterView.contains(view)) {
            mFooterView.remove(view);
            notifyDataSetChanged();
        }
    }

接下来在创建ViewHolder时就要根据position的位置进行判断,如果是头部就床架头部的ViewHolder,内容就创建内容的ViewHolder,底部就创建底部的ViewHolder;

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
        int headerCount = getHeaderCount();
        if (position < headerCount) {
            //头部
            return createHeaderViewHolder(mHeaderView.get(position));
        }
        int adjPosition = position - headerCount;
        int adapterCount = 0;
        if (mAdapter != null) {
            //内容区域
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.onCreateViewHolder(parent,mAdapter.getItemViewType(adjPosition));
            }
        }
        //底部
        return createFooterViewHolder(mFooterView.get(adjPosition - adapterCount));
    }

    /**
     * 创建头部viewholder
     *
     * @param view
     */
    private RecyclerView.ViewHolder createHeaderViewHolder(View view) {
        return new RecyclerView.ViewHolder(view) {
        };
    }

    /**
     * 创建底部viewholder
     *
     * @param view
     * @return
     */
    private RecyclerView.ViewHolder createFooterViewHolder(View view) {
        return new RecyclerView.ViewHolder(view) {
        };
    }

在绑定参数时头部和底部就不需要进行处理,只需要处理内容区域就可以了;

 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int numHeaders = getHeaderCount();
        if (position < numHeaders) {
            //如果是头部直接返回
            return;
        }
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                mAdapter.onBindViewHolder(holder,adjPosition);
            }
        }
    }

使用时,在实例化头部或底部view时,parent的传入,要传入当前的RecyclerView;

recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter();
WrapRecyclerAdapter adapter=new WrapRecyclerAdapter(recyclerAdapter);
recyclerView.setAdapter(adapter);

View headerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加头部
adapter.addHeaderView(headerView);
View footerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加底部
adapter.addFooterView(footerView);

这样就可以对RecyclerView进行添加头部或者底部了,但是每次使用的时候都需要创建两个adapter,有点麻烦,并且这样子调用也不符合迪米特原则(最少知识原则),最好能弄成ListView那样就最好了;那就继续往下走吧,自定义一个RecyclerView,重写setAdaper方法,并新增添加头部/删除头部、添加底部/删除底部的方法;

public class WrapRecyclerView extends RecyclerView {
    private WrapRecyclerAdapter mAdapter;

    public WrapRecyclerView(Context context) {
        this(context, null);
    }

    public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    @Override
    public void setAdapter(Adapter adapter) {
        mAdapter = new WrapRecyclerAdapter(adapter);
        super.setAdapter(mAdapter);
    }
    /**
     * 添加头部
     *
     * @param view
     */
    public void addHeaderView(View view) {
        if (mAdapter!=null) {
            mAdapter.addHeaderView(view);
        }
    }

    /**
     * 添加底部
     *
     * @param view
     */
    public void addFooterView(View view) {
        if (mAdapter!=null) {
            mAdapter.addFooterView(view);
        }
    }

    /**
     * 移除头部
     *
     * @param view
     */
    public void removeHeaderView(View view) {
        if (mAdapter!=null) {
            mAdapter.removeHeaderView(view);
        }
    }

    /**
     * 移除底部
     *
     * @param view
     */
    public void removeFooterView(View view) {
        if (mAdapter!=null) {
            mAdapter.removeFooterView(view);
        }
    }
}

需要注意,必须要设置了adapter才可以添加头部和底部;

recyclerView = (WrapRecyclerView) findViewById(R.id.id_recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter();
//WrapRecyclerAdapter adapter=new WrapRecyclerAdapter(recyclerAdapter);
recyclerView.setAdapter(recyclerAdapter);

View headerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加头部
recyclerView.addHeaderView(headerView);
View footerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加底部
recyclerView.addFooterView(footerView);

这样子就和ListView的添加头部和底部使用一样了。

 

源码 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章