RecyclerView详细用法

上一篇,RecyclerView基本用法

上一篇文章简单说了一下RecyclerView的基本用法,本篇文章打算说一下RecyclerView的详细用法,主要包含RecyclerView添加分割线及点击事件功能。其实主要也是打算看一下RecyclerView的源码,先把基本用法记录下来。这文章也是以前写的,现在只是搬过来一下,方便自己以后需要用到的时候查看,也方便自己更好的研究RecyclerView的源码,毕竟最基础的用法都不懂,谈什么看源码。

一、RecyclerView item点击事件实现

package recyclerview.xiaochao.com.recyclerviewdemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * @author xiaochao
 * @description RecyclerView适配器
 * @time 2017/12/23 10:46
 */
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    //1.我们首先在MyAdapter中编写一个内部类MyViewHolder继承自RecyclerView.ViewHolder
    class MyViewHolder extends RecyclerView.ViewHolder {
        private TextView tv;
        public MyViewHolder(View itemView) {
            super(itemView);
            tv = itemView.findViewById(R.id.tv);//此id为item布局中TextView的id
        }
    }

    //2.让MyAdapter继承RecyclerView.Adapter<MyAdapter.MyViewHolder>,注意<>中是我们自定义的ViewHolder

    private List<String> mList;
    private Context mContext;

    //3.通过构造函数传入数据与Context
    public MyAdapter(Context context, List<String> stringList) {
        mContext = context;
        mList = stringList;
    }

    /**
     * 加载条目布局
     *
     * @param parent
     * @param viewType 可以根据这个值加载不同的布局
     * @return RecyclerView中的每一个itemView
     */
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_recyclerview, parent, false);
        MyViewHolder viewHolder = new MyViewHolder(itemView);
        return viewHolder;
    }

    /**
     * 将视图与数据进行绑定
     *
     * @param holder   可以将其看成itemView,onCreateViewHolder方法中返回的就是MyViewHolder
     * @param position
     */
    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        holder.tv.setText(mList.get(position));
        if(mOnItemClickListener!=null){//当mOnItemClickListener不为null时,
        //说明RecyclerView已经调用了setOnItemClickListener(OnItemClickListener onItemClickListener)方法
            holder.tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int pos = holder.getLayoutPosition();//获取点击的索引
                    mOnItemClickListener.onItemClick(holder.tv,pos);//执行onItemClick方法,具体实现在外部调用的时候实现
                }
            });
            holder.tv.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    int pos = holder.getLayoutPosition();//获取点击的索引
                    mOnItemClickListener.onItemLongClick(holder.tv,pos);
                    return false;
                }
            });
        }
    }

    /**
     * @return 要显示多少个item
     */
    @Override
    public int getItemCount() {
        return mList.size();
    }

    /**
     * 定义接口,可以到外部类去定义
     */
    public interface OnItemClickListener{
        void onItemClick(View view,int position);//item点击事件
        void onItemLongClick(View view,int position);//item长按事件
    }

    //在适配器中申明我们定义的接口,让它为null
    public OnItemClickListener mOnItemClickListener=null;

    /**
     * 为了给外部也就是我们new出来的该对象调用,将OnItemClickListener传入进来赋值给我们申明的接口mOnItemClickListener
     * 具体实现方法包括item点击与长按的实现都在外部调用的时候实现
     * @param onItemClickListener
     */
    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.mOnItemClickListener = onItemClickListener;
    }

}

然后我们在Activity中调用,处理点击事件回调

mMyAdapter = new MyAdapter(MainActivity.this, mList);
mMyAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show();
            }

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

二、RecyclerView长按删除item实现

有时候我们需要能够将item移除,这个其实很好实现,只要在Adapter中增加几行代码即可。如上,我们已经实现了item的点击与长按事件,我们将删除item的功能放在长按事件里去实现,代码如下:首先在Adapter中增加删除item的方法,用来删除点击的item,代码如下:

public void removeData(int position){
       mList.remove(position);
       notifyItemRemoved(position);
   }

接下来就是在Adapter调用setOnItemClickListener实现onItemLongClick方法时调用removeData方法:

mMyAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
           @Override
           public void onItemClick(View view, int position) {
               Toast.makeText(MainActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show();
           }

           @Override
           public void onItemLongClick(View view, final int position) {
               new AlertDialog.Builder(MainActivity.this)
                       .setTitle("确认删除吗?")
                       .setNegativeButton("取消",null)
                       .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                           @Override
                           public void onClick(DialogInterface dialogInterface, int i) {
                               mMyAdapter.removeData(position);//这里执行删除item方法
                           }
                       }).show();
           }
       });

三、给item之间添加分割线

前面说了,RecyclerView中的item默认是没有分割线的,而ListView默认是有分割线的,那么我们如果需要加上分割线,该如何加呢?这里也不用太担心,RecyclerView提供了让我们自定义分割线的方法,首先我们需要自己定义一个类去继承RecyclerView.ItemDecoration,然后我们就可以自己开始实现去绘制我们想要的分割线了

public class DividerItemDecoration 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 DividerItemDecoration(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, RecyclerView.State state) {
        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);
            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, View view, RecyclerView parent, RecyclerView.State state) {
        if(mOrientation==VERTICAL_LIST){
            outRect.set(0,0,0,mDivider.getIntrinsicHeight());
        }else{
            outRect.set(0,0,mDivider.getIntrinsicWidth(),0);
        }
    }
}

上面代码就是自己定义的一个简单的分割线类,上面我们只是把它定义出来,使用的话只需要一行代码就可以搞定,执行完下面步骤后,我们的RecyclerView中的item之间就有分割线了

mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));

Android RecyclerView 使用完全解析 体验艺术般的控件


版权声明:本文为xiaochao_develop原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。