RecyclerView的使用

1.RecyclerView的基本使用方法:

RecyclerView:
A flexible view for providing a limited window into a large data set.
就是说RecyclerView可以像ListView,GridView一样展示大数据集合的组件。

使用方式当然也和ListView 相似,但是要比ListView稍微复杂一点点,因为他的可扩展性更强。

1. 需要在build.gridle中的dependencied块中添加依赖


compile 'com.android.support:recyclerview-v7:25.0.0'

2. 然后就可以在布局中引入RecyclerView了

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

3. 声明FirstAdapter类继承RecyclerView.Adapter

public class FirstAdapter extends RecyclerView.Adapter<FirstAdapter.FirstViewHolder> {
    private List<String> mDataList;

    public FirstAdapter() {
        this(null);
    }

    public FirstAdapter(List<String> dataList) {
        this.mDataList = mDataList == null ? new ArrayList<String>() : dataList;
    }

  /**
     * 向RecyclerView填充数据
     *
     * @param dataList 数据集合
     */
    public void setData(List<String> dataList) {
        if (dataList == null)
            return;
        this.mDataList = dataList;
        notifyDataSetChanged();
    }

    //顾名思义,这个方法要返回一个ViewHolder对象
    @Override
    public FirstViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout_recycler_main, null);
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) convertView.getLayoutParams();
        if (params == null) {
            params = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        convertView.setLayoutParams(params);
        return new FirstViewHolder(convertView);
    }

    //绑定数据
    @Override
    public void onBindViewHolder(FirstViewHolder holder, int position) {
        holder.id_tv_name.setText(mDataList.get(position));
    }

    @Override
    public int getItemCount() {
        return mDataList.size();
    }
    //声明内部类FirstViewHolder
    static class FirstViewHolder extends RecyclerView.ViewHolder {
        TextView id_tv_name;

        public FirstViewHolder(View itemView) {
            super(itemView);
            id_tv_name = (TextView) itemView.findViewById(R.id.id_tv_name);
        }
    }
}

4. 在Activity使用

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private FirstAdapter mAdapter;
    private ItemTouchHelper mItemTouchHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
    }

    private void initData() {
        List<String> dataList=new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            dataList.add("---->"+i);
        }
        mAdapter.setData(dataList);
    }

    private void initView() {

        mRecyclerView= (RecyclerView) findViewById(R.id.id_recycler_view);
        //确保RecyclerView的尺寸是个常数,可以查看源码,false的时候代价很大。
        mRecyclerView.setHasFixedSize(true);
        //设置RecyclerView的布局管理器,这里使用线性布局管理器LinearLayoutManager
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        //设置RecyclerView的Item动画,这里使用默认动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        //绑定Adapter
        mAdapter=new FirstAdapter();
        mRecyclerView.setAdapter(mAdapter);
    }
}

至此,就可以正常显示数据了,但是会发现没有分割线。这个随后再说,我们先来设置RecyclerView 的点击事件.

2.RecyclerView的点击事件:

我们要设置RecyclerView 的点击事件,发现它并没有类似ListView,GridView的setOnItemClickListener,那么怎么办呢?
一种方法是,我们可以在Adapter中声明一个接口,利用接口回调的方法事件itemView的点击事件。原来我一直都用的这种方法,感觉并不好用,毕竟咱们需要的是RecyclerView的点击事件,设置在Adapter中好像有点变味儿。

第二种方法是通过设置RecyclerView的addOnItemTouchListener,利用手势检测GestureDetectorCompat实现的,这是刚从一个博客中看到的,感觉很不错,就在这里记录一下。

步骤:
1. 声明一个抽象类实现RecyclerView的OnItemTouchListener接口,并重写其中的方法,需要在构造方法中传入RecyclerView
2. 定义抽象方法OnItemClick,OnItemLongClick分别表示单击事件和长按事件。
3. 该类需要持有GestureDetectorCompat对象,所有的触摸事件都交给GestureDetectorCompat处理,因此需要声明一个内部类OnItemTouchHelperGestureListener继承SimpleOnGestureListener,并实现onSingleTapUp(单击事件),onLongPress(长按事件)方法。
4. 在Activity中直接调用RecyclerView的addOnItemTouchListener即可使用

具体代码如下

/**
 * 类功能描述:实现RecyclerView 的单击和长按时间
 * 1.该类需要持有当前RecyclerView对象
 * 2.该类需要持有GestureDetectorCompat对象,方便进行手势检测
 */

public abstract class OnRecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
    private GestureDetectorCompat mGestureDetectorCompat;
    private RecyclerView mRecyclerView;

    /**构造方法
     * 1.传入RecyclerView
     * 2.创建手势检测器对象
     * @param mRecyclerView
     */
    public OnRecyclerItemClickListener(RecyclerView mRecyclerView) {
        this.mRecyclerView = mRecyclerView;
        mGestureDetectorCompat = new GestureDetectorCompat(mRecyclerView.getContext(), new OnItemTouchHelperGestureListener());
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        //交给手势检测器处理
        mGestureDetectorCompat.onTouchEvent(e);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        //交给手势检测器处理
        mGestureDetectorCompat.onTouchEvent(e);
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        //不用管
    }

    /**单击事件
     * @param viewHolder viewholder
     */
    public abstract void OnItemClick(RecyclerView.ViewHolder viewHolder);

    /**长按事件
     * @param viewHolder
     */
    public abstract void OnItemLongClick(RecyclerView.ViewHolder viewHolder);

    /**
     * 手势检测器实现类,该类实现了单击和长按事件
     */
    class OnItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {
        /**该方法会在点击弹起手指的时候调用,可以用来处理单击操作
         * @param e
         * @return
         */
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
            if (childView != null) {
                RecyclerView.ViewHolder viewHolder = mRecyclerView.getChildViewHolder(childView);
                OnItemClick(viewHolder);
            }
            return true;
        }

        /**长按操作
         * @param e
         */
        @Override
        public void onLongPress(MotionEvent e) {
            View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
            if (childView != null) {
                RecyclerView.ViewHolder viewHolder = mRecyclerView.getChildViewHolder(childView);
                OnItemLongClick(viewHolder);
            }
        }
    }
}

具体调用:

 mRecyclerView.addOnItemTouchListener(new OnRecyclerItemClickListener(mRecyclerView){
            @Override
            public void OnItemClick(RecyclerView.ViewHolder viewHolder) {
                int position=viewHolder.getLayoutPosition();
                Toast.makeText(MainActivity.this,"--->单击:"+mAdapter.getItem(position),Toast.LENGTH_SHORT).show();
            }

            @Override
            public void OnItemLongClick(RecyclerView.ViewHolder viewHolder) {
                int position=viewHolder.getLayoutPosition();
                Toast.makeText(MainActivity.this,"--->长按:"+mAdapter.getItem(position),Toast.LENGTH_SHORT).show();
                if (position!=0){
                   mItemTouchHelper.startDrag(viewHolder);
                }
            }
        });

这样的使用方法很像ListView了是吧。我们直接在View上设置View的监听事件,而不是通过adapter去设置,起码在理解上我觉得更简单了。
这里写图片描述

3.RecyclerView的分割线:

RecyclerView不能直接在xml中通过divider属性设置分割线,只能在代码中通过addItemDecoration方法去设置,该方法需要传入一个 ItemDecoration 对象

public void addItemDecoration(ItemDecoration decor) {}

系统并没有给我们提供默认的分割线实现类。一切都需要我们自己去做。

自定义分割线的步骤:
1. 声明分割线类DefaultDecoration,并重写getItemOffsets()方法

public class DefaultDecoration extends RecyclerView.ItemDecoration {
    public DefaultDecoration() {
        super();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
    }

    /**
     * 此方法会在ItemView布局之前调用
     *
     * @param outRect 可以理解为ItemView外边一层的一个Rect
     * @param view    当前ItemView
     * @param parent  当前的RecyclerView
     * @param state   RecyclerView的状态
     */
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (parent.getChildAdapterPosition(view) != 0) {
            outRect.top = 1;
        }
    }
}

这里写图片描述

这是最简单的一种情况,需要给RecyclerView设置一个背景色,分割线的颜色就是RecyclerView的背景色。如果想让分割显得颜色区别于背景色,这个方法是没法实现的。
下面介绍第二种方法。

第二种方法:

public class ColorDividerItemDecoration extends RecyclerView.ItemDecoration {
    // 分割线的高度
    private float mDividerHeight;
    //画壁
    private Paint mPaint;

    public ColorDividerItemDecoration() {
        //初始化画笔
        mPaint=new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.BLUE);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        int childCount=parent.getChildCount();
        //遍历所有的child,给每一个child都画上分割线
        for (int i = 0; i < childCount; i++) {
            View childView=parent.getChildAt(i);
            int index=parent.getChildAdapterPosition(childView);
            if (index==0)
                continue;
            float top=childView.getTop()-mDividerHeight;
            float left=parent.getPaddingLeft();
            float right=parent.getWidth()-parent.getPaddingRight();
            float bottom=childView.getTop();
            c.drawRect(left,top,right,bottom,mPaint);
        }
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
    }

    /**计算出每一个ItemView的偏移量
     * @param outRect
     * @param view
     * @param parent
     * @param state
     */
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (parent.getChildAdapterPosition(view)!=0){
            outRect.top=1;
            mDividerHeight=1;
        }
    }
}

这里需要注意的是在onDraw()方法中计算分割线的rect坐标。从列表上看,分割线就相当于从第二个item开始,坐标为getPaddingLeft(),iteView.getTop-mDividerHeight,getWidth()-getPaddingRight(),itemView.getTop()的一个矩形区域
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对你的问题,以下是一个简单的 RecyclerView 使用示例: 1. 在布局文件中添加 RecyclerView ``` <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 2. 在 Activity 或 Fragment 中获取 RecyclerView 对象并设置 LayoutManager ``` RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); ``` 3. 创建 Adapter 类并实现 onCreateViewHolder()、onBindViewHolder() 和 getItemCount() 方法 ``` public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private List<String> mData; public MyAdapter(List<String> data) { mData = data; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view, parent, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { String text = mData.get(position); holder.textView.setText(text); } @Override public int getItemCount() { return mData.size(); } static class MyViewHolder extends RecyclerView.ViewHolder { TextView textView; public MyViewHolder(View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ``` 4. 将 Adapter 实例设置给 RecyclerView ``` MyAdapter myAdapter = new MyAdapter(data); recyclerView.setAdapter(myAdapter); ``` 其中,item_view.xml 是每个 item 的布局文件,可以根据需求自定义。这样就完成了 RecyclerView 的基本使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值