简单实现RecyclerView的效果

话不多说,先上图:

recyclerview获取可见的item数据 使用recyclerview_谷歌


RecyclerView简介

从Android 5.0开始,谷歌公司推出了RecylerView控件,RecyclerView是support-v7包中的新组件,Google的官方文档中介绍的,RecyclerView用于在有限的窗口展现大量的数据。其实体现该作用的组件已经有了ListView、GridView,那么为什么还要有RecyclerView的出现呢?
以下摘自鸿洋大神的博客:
整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。

  • 你想要控制其显示的方式,请通过布局管理器LayoutManager
  • 你想要控制Item间的间隔(可绘制),请通过ItemDecoration
  • 你想要控制Item增删的动画,请通过ItemAnimator
  • 你想要控制点击、长按事件,请自己写(这一点有点坑,其实我们通过自己抽取接口,完成类似ListView的onItemClickListener()的功能,接下来的代码分析将做这方面的实现)

RecyclerView的Demo代码实现

$1、RecyclerViewActivity:
该类是实例化RecyclerView的Activity类,可以关联适配器类对数据进行显示,可以根据不同的布局需求调用LayoutManager控制显示布局(比如ListView、GridView、瀑布型),可通过ItemAnimator以添加Item增删的动画,可以控制点击事件,还可以自定义分割线。

public class RecyclerViewActivity extends Activity implements View.OnClickListener {

    private Button btn_add;
    private Button btn_delete;
    private Button btn_list;
    private Button btn_grid;
    private Button btn_flow;
    private RecyclerView recyclerview;
    private TextView tv_title;

    private ArrayList<String> datas;
    private MyRecyclerViewAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();

        initData();

        //设置RecyclerView的适配器
        adapter = new MyRecyclerViewAdapter(RecyclerViewActivity.this,datas);
        recyclerview.setAdapter(adapter);

        //LayoutManager
        recyclerview.setLayoutManager(new LinearLayoutManager(RecyclerViewActivity.this, LinearLayoutManager.VERTICAL, false));
//        recyclerview.scrollToPosition(datas.size()-1);

        //添加RecyclerView的分割线
        recyclerview.addItemDecoration(new DividerListItemDecoration(RecyclerViewActivity.this,DividerListItemDecoration.VERTICAL_LIST));

        //设置点击某条的监听
        adapter.setOnItemClickListener(new MyRecyclerViewAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, String data) {
                Toast.makeText(RecyclerViewActivity.this, "data=="+data, Toast.LENGTH_SHORT).show();
            }
        });


        //设置动画
        recyclerview.setItemAnimator(new DefaultItemAnimator());

    }

    private void initData() {
        datas = new ArrayList<>();
        //准备数据集合
        for (int i=0;i<100;i++){
            datas.add("Content_"+i);
        }
    }

    private void initView() {
        setContentView(R.layout.activity_recyclerview);
        btn_add = (Button) findViewById(R.id.btn_add);
        btn_delete = (Button) findViewById(R.id.btn_delete);
        btn_list = (Button) findViewById(R.id.btn_list);
        btn_grid = (Button) findViewById(R.id.btn_grid);
        btn_flow = (Button) findViewById(R.id.btn_flow);
        recyclerview = (RecyclerView) findViewById(R.id.recyclerview);
        tv_title = (TextView) findViewById(R.id.tv_title);
        tv_title.setText("RecyclerView");

        //设置点击事件
        btn_add.setOnClickListener(this);
        btn_delete.setOnClickListener(this);
        btn_list.setOnClickListener(this);
        btn_grid.setOnClickListener(this);
        btn_flow.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_add:
                adapter.addData(0,"New_Content");
                recyclerview.scrollToPosition(0);
                break;
            case R.id.btn_delete:
                adapter.removeData(0);
                break;
            case R.id.btn_list:
                //设置List类型效果
                recyclerview.setLayoutManager(new LinearLayoutManager(RecyclerViewActivity.this,LinearLayoutManager.VERTICAL,false));
                break;
            case R.id.btn_grid:
                //设置Grid类型效果
                recyclerview.setLayoutManager(new GridLayoutManager(RecyclerViewActivity.this, 2, GridLayoutManager.VERTICAL, false));
//                recyclerview.scrollToPosition(99);
                break;
            case R.id.btn_flow:
                //设置瀑布流类型效果
                recyclerview.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));
                break;
        }
    }
}

$2、MyRecyclerViewAdapter:
该类是适配器类,为了提供类似ListView、GridView的点击事件,在该类中封装了一个接口,提供给调用者类抽取。

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {


    private final Context context;
    private  ArrayList<String> datas;

    public MyRecyclerViewAdapter(Context context, ArrayList<String> datas) {
        this.context = context;
        this.datas = datas;
    }

    /**
     * 相当于于getView方法中创建View和ViewHolder
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = View.inflate(context, R.layout.item_recyclerview,null);
        return new ViewHolder(itemView);
    }

    /**相当于于getView绑定数据部分的代码
     * 数据和View绑定
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        //根据位置得到对应的数据
        String  data  = datas.get(position);
        holder.tv_title.setText(data);

    }

    /**
     * 得到总条数
     * @return
     */
    @Override
    public int getItemCount() {
        return datas.size();
    }

    /**
     * 添加数据
     * @param position
     * @param data
     */
    public void addData(int position, String data) {
        datas.add(position,data);
        //刷新适配器
        notifyItemInserted(position);
    }

    /**
     * 移除数据
     * @param position
     */
    public void removeData(int position) {
        datas.remove(position);
        //刷新适配器
        notifyItemRemoved(position);
    }

    class ViewHolder extends RecyclerView.ViewHolder {

        private ImageView iv_icon;
        private TextView tv_title;

        public ViewHolder(View itemView) {
            super(itemView);
            iv_icon = (ImageView) itemView.findViewById(R.id.iv_icon);
            tv_title = (TextView) itemView.findViewById(R.id.tv_title);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

//                    Toast.makeText(context, "data=="+datas.get(getLayoutPosition()), Toast.LENGTH_SHORT).show();
                    if(onItemClickListener != null){
                        onItemClickListener.onItemClick(v,datas.get(getLayoutPosition()));
                    }
                }
            });

            iv_icon.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "我是图片=="+getLayoutPosition(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    /**
     * 点击RecyclerView某条的监听
     */
    public interface OnItemClickListener{

        /**
         * 当RecyclerView某个被点击的时候回调
         * @param view 点击item的视图
         * @param data 点击得到的数据
         */
        public void onItemClick(View view, String data);

    }

    private  OnItemClickListener onItemClickListener;

    /**
     * 设置RecyclerView某个的监听
     * @param onItemClickListener
     */
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }
}

$3、DividerListItemDecoration:
自定义分割线,继承自RecyclerView.ItemDecoration,可以当成万用分割线的模板代码。

public class DividerListItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    private Drawable mDivider;

    private int mOrientation;

    public DividerListItemDecoration(Context context, int orientation) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent) {
//        Log.e("recyclerview - itemdecoration", "onDraw()");

        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }

    }


    public void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            RecyclerView v = new RecyclerView(parent.getContext());
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }
}

以上就是所有的代码实现,接下来分析一下,RecyclerView实现了哪些:

  • 系统提供了几种LayoutManager的使用
    比方说我们可以在ListView、GridView中设置横向ListView、横向GridView的效果,这里举例横向ListView,我们只要在修改代码
case R.id.btn_list:
                //设置List类型效果
                recyclerview.setLayoutManager(new LinearLayoutManager(RecyclerViewActivity.this,LinearLayoutManager.VERTICAL,false));
                break;

为:

case R.id.btn_list:
                //设置List类型效果
                recyclerview.setLayoutManager(new LinearLayoutManager(RecyclerViewActivity.this,LinearLayoutManager.HORIZONTAL,false));
                break;

即可完成ListView的横向效果:

recyclerview获取可见的item数据 使用recyclerview_ide_02

  • 实现了自定义分割线的效果,我们还可以使用系统自定义的分割线,代码可以修改这部分代码
//添加RecyclerView的分割线
        recyclerview.addItemDecoration(new DividerListItemDecoration(RecyclerViewActivity.this,DividerListItemDecoration.VERTICAL_LIST));

改成:
//首先在分割线类DividerListItemDecoration中增加第三个参数的构造

public DividerListItemDecoration(Context context, int orientation, int drawableId) {
        this(context, orientation);
        mDivider = ContextCompat.getDrawable(context, drawableId);
    }
recyclerview.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST,R.drawable.divider_mileage));

使用系统自定义的分割线的好处是可以在资源文件中修改分割线的属
性,在资源文件中我们也可以定义分割线的样式。


自定义drawable文件一份:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size android:height="20dp" />
    <solid android:color="#ff992900" />
</shape>

可见效果如下所示:

recyclerview获取可见的item数据 使用recyclerview_android_03


我们可以根据自己的喜好,设置各种各样的分割线,是不是更加好玩了~

  • 实现增删Item的动画设置
    简简单单一行代码
//设置动画
recyclerview.setItemAnimator(new DefaultItemAnimator());

这里完成功能的动画是系统默认的动画,我们也可以自定义动画效果,这里就不做演示了。

  • 实现onclick点击事件,很简单,创建一个接口,提供一个设置入口,然后在onBindViewHolder中判断即可。最后在主Activity中设置监听:
//设置点击某条的监听
        adapter.setOnItemClickListener(new MyRecyclerViewAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, String data) {
                Toast.makeText(RecyclerViewActivity.this, "data=="+data, Toast.LENGTH_SHORT).show();
            }
        });

至此,RecyclerView之旅已经结束了,我们可以看到,这种插拔式的组件带来的可能性和丰富性,让我们迫不及待地想给自己的想象力和创造力 插上翅膀,言之有些夸张了哈。唔哈哈好好学习!