RecylclerView入门初步

Posted by 夏敏的博客 on August 9, 2016

RecyclerView可以看作是ListView的进化版本,当然RecyclerView并不是继承ListView的,RecyclerView直接继承于ViewGroup父类。RecyclerView的灵活性与可替代性比listview更好,我们可以很方便的使用它完成ListView比较难完成的效果。

现在,我们开始学习如何使用它:

- 添加依赖

      compile 'com.android.support:recyclerview-v7:21.0.+'

- 在xml中配置

 <android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    />

- Acitvity中使用

    RecyclerView mRecyclerView;
    RecyclerViewAdapter mAdapter;
    LinearLayoutManager mLayoutManager;

    mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    mLayoutManager = new LinearLayoutManager(this);

    //改变方向
    //mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

    mRecyclerView.setLayoutManager(mLayoutManager);
    //添加间隔行,若不添加该句注释即可 RecycleViewDivider为RecyclerView.ItemDecoration的实现类
    mRecyclerView.addItemDecoration(new RecycleViewDivider(this, LinearLayoutManager.HORIZONTAL));
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());

    mAdapter =  new RecyclerViewAdapter(mdatas);
    mRecyclerView.setAdapter(mAdapter);

可以看到,RecyclerView并不像ListView那样只要设个adpter就完成了,它有很多自己可自定义的功能,可以很方便的完成很多效果。
比如: mRecyclerView.setLayoutManager(mLayoutManager); 就给了程序员很大的发挥空间,因为有了布局管理,我们可以很方便的设置为
LinearLayoutManager 线性布局同时支持横向、纵向
GridLayoutManager时 为网格布局管理器
StaggeredGridLayoutManager 瀑布式布局管理器

- 适配器编写

RecycleView是对ListView以及GridView的升级,在使用的时候同源更新需要使用Adapter适配器。但是RecycleView使用的适配器并不是之前的BaseAdapter了。RecycleView使用的适配器需要继承RecyclerView.Adapter\

我们将适配器的编写流程分为:

1.继承 RecyclerView.Adapter

2.完成内部类 ViewHolder 这个 ViewHolder不再是以前的BaseAdapter时我们写的ViewHolder,而是需要继承RecyclerView.ViewHolder抽象类的ViewHolder

3.编写构造方法

4.onBindViewHolder中进行每个item的操作

5.若需要监听点击事件,我们需要定义回调接口,并在第四步进行item的view操作时,添加监听事件回掉该接口

以下便是我的RecyclerViewAdapter代码

/**
 * Created by Xiamin on 2016/9/2.
 */
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
    ListView
    private List<String> mdata;

    public RecyclerViewAdapter(List<String> data) {
        mdata = data;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_item, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        holder.textView.setText(mdata.get(position));

        /**
         * 在绑定viewholder时 给每个view设置上触摸监听
         */
        if (mOnItemClickListener != null) {
            holder.textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mOnItemClickListener.onItemClick(holder.itemView, position);
                }
            });

            holder.textView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    mOnItemClickListener.onItemLongClick(holder.itemView, position);

                    //返回true 这样触发了onLongClick后便不会再触发onClick了
                    return true;
                }
            });
        }
    }

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

    /**
     * 定义接口用于短按长按的回调
     */
    public interface OnRecyclerViewItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    /**
     * 添加点击事件
     */
    private OnRecyclerViewItemClickListener mOnItemClickListener = null;

    public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) {
        this.mOnItemClickListener = listener;
    }


    public void addData(int position) {
        mdata.add(position, "Insert One");
        notifyItemInserted(position);
    }

    public void removeData(int position) {
        mdata.remove(position);

        notifyItemRemoved(position);
        /**
         * 非常重要!!! 若不使用该方法通知适配器数据已经变了,notifyItemRemoved会导致item下标错乱
         * 因为删除某一项时调用notifyItemRemoved后,显示的item是不会调用onBind方法的,
         * 所以position并没有被刷新。这时候得到的position值就是错误的。
         */
        notifyItemRangeChanged(position, mdata.size());

    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        public TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.textView);
        }
    }
}

- 初步运行

发现可以运行,类似于简单的listview(当然,item的xml配置代码被我省略了)

  • 添加监听事件

我选择在长按item时删除该item,删除动画在由该行设置

 mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter.setOnItemClickListener(new RecyclerViewAdapter.OnRecyclerViewItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this, position + "pressed", LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(MainActivity.this, position + "Longpressed", LENGTH_SHORT).show();
                mAdapter.removeData(position);
            }
        });

- 遇坑

完成该功能后,测试发现,删除会出现问题,动画是有了,但是下标会乱,导致删除错误item、
因此便有了该行代码。
因为删除某一项时调用notifyItemRemoved后,显示的item是不会调用onBind方法的,所以position并没有被刷新。这时候得到的position值就是错误的。我们需要手动使adapter给后面的item重新onBind

notifyItemRangeChanged(position, mdata.size());

至此,RecyclerView的便正常工作了。

总结

 本文只是RecyclerView的一些基本使用,有很多强大的功能还未能接触,本文也比较初步,仅作入门引导。
作者:Anderson大码渣,欢迎关注我的简书: Anderson大码渣