Android-Recyclerview常用总结

概述

在android开发中我们不可避免的会用到Recyclerview,用以替代之前的ListView,GridView,Gallery等.它是support:recyclerview-v7中提供的控件,最低兼容到android 3.0版本.之前listview难以实现或者不能实现的效果,它都可以实现或者轻松实现. 1.那么它有哪些优势呢? 总结也就一句话:高类聚低耦合.RecyclerView已经标准化ViewHolder,我们自定义的ViewHoler需要继承 RecyclerView.ViewHolder,然后在构造方法中初始化控件. 2.如何添加依赖?

- implementation 'com.android.support:recyclerview-v7:26.1.0'
  如果只是用到recyclerview控件优先选用此依赖方式
- implementation 'com.android.support:design:26.1.0'
  通过添加MD的disign包方式使用该控件,内部包含多种MD控件如:SnakeBar,

3.有哪些常用操作?

  • LayoutManager,布局管理器,控制其显示的方式。
  • ItemDecoration,控制Item间的间隔(允许绘制)。
  • ItemAnimator,控制Item增删的动画。

使用

recyclerview的布局管理器有三种分别是线性布局管理器(LinearLayoutManager);表格布局管理器(GridLayoutManager);瀑布流布局管理器(StaggeredGridLayoutManager)。这个不做详细介绍。简单上一下代码。

       //设置为线性管理器
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        //设置为表格管理器
        mRecyclerView.setLayoutManager(new GridLayoutManager(this,3));
        //瀑布流管理器
        StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(manager);
        //设置item增加删除动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        //给item增加自带分割线
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));

关于RecyclerView设置分割线和增加删除动画我们这里使用的是默认你都可以自定义,这个无所谓。

1.item的监听

不知道为啥recycleerview没有提供监听方法,这就要我们手动写相关代码了,这个实现方式一般有两种。前者是通过对Recyclerview触摸的监听,后者是自定义接口实现接口回调。后者相对简单,在我们的adapter中我们来搞一下:

item的监听 方式一
 private OnItemClickLitener mOnItemClickLitener;

    public interface OnItemClickLitener
    {
        void onItemClick(View view, int position);
        void onItemLongClick(View view , int position);
    }

    public void setOnItemClickLitener(OnItemClickLitener OnItemClickLitener)
    {
        this.mOnItemClickLitener = OnItemClickLitener;
    }

然后设置监听回调:

  @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        holder.tvName.setText(mArrayList.get(position).name);
        holder.tvSex.setText(mArrayList.get(position).sex);
        holder.tvAge.setText(mArrayList.get(position).age + "");

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null) {
            holder.LinearItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.LinearItem.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    return false;
                }
            });

        }
    }

在写一个增加和减少item的方法:

    public void addItem(int position) {
        RecyclerViewBean mRecyclerViewBean =new RecyclerViewBean("增加用户"+position,100,"nan");
        mArrayList.add(position, mRecyclerViewBean);
        notifyItemInserted(position);
    }

    public void removeItem(int position) {
        mArrayList.remove(position);
        notifyItemRemoved(position);
    }

设置adaper监听:

mRecyclerViewAdapter.setOnItemClickLitener(new RecyclerViewAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(View view, int position) {
                mRecyclerViewAdapter.addItem(position);
            }

            @Override
            public void onItemLongClick(View view, int position) {
                mRecyclerViewAdapter.removeItem(position);
            }
        });
item的监听 方式二(对recyclerview触摸实现监听)

这个相对有一点难度,在这个之前我们要先来了解一个手势识别类----》GestureDetectorCompat 如果你不了解GestureDetectorCompat那么你一定知道onTouchEvnet,我们刚开始都是通过View.OnTouchListener内部接口,通过重写他的[onTouch]方法,获取Action来判断move,up,down动作,如下:

 mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
 int action = MotionEventCompat.getActionMasked(event);
    switch(action) {
        case (MotionEvent.ACTION_DOWN) :
            Log.d(DEBUG_TAG,"Action was DOWN");
            return true;
        case (MotionEvent.ACTION_MOVE) :
            Log.d(DEBUG_TAG,"Action was MOVE");
            return true;
        case (MotionEvent.ACTION_UP) :
            Log.d(DEBUG_TAG,"Action was UP");
            return true;
       default : 
            return super.onTouchEvent(event);

            }
        });

不陌生吧,但是这个监听只能应对一些简单的操作,如果是一些比较复杂的,比如:根据用户触摸的轨迹去判断是什么手势就显得吃力了,所以Android sdk给我们提供了GestureDetectorCompat(Gesture:手势Detector:识别)类,更高效。

GestureDetectorCompat类是GestureDetector的替代,它的创建方式有两种,我们选第一种方式

image.png

它是V4包下的。这不是重点,重点是我们怎么用它,感兴趣的小伙伴自行百度。 先来说一下我们的思路: 给Recyclerview设置添加OnItemTouchListener监听重写其方法,然后创建GestureDetectorCompat对象,通过一个手势探测器 GestureDetectorCompat 来探测屏幕事件,然后通过手势监听器 SimpleOnGestureListener 来识别具体事件种类,对应回调,算了上代码吧

PjuDEV.md.png

Pjus4U.md.png

RecyclerView的addOnItemTouchListener监听

PjuQBt.png

ItemTouchListener这个类提出来单独使用,可以减少每个adapter中都定义一个接口回调,优化性能还高大上

2.RecyclerView之ItemDecoration

2.1.itemDecoration 简单使用

2.1.1 itemDecoration 简单使用针对LinearLayoutManager
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));

大家都注意到我们给recyclerview设置的这个属性了吧,这个属性就是使用其默认的ItemDecoration, DividerItemDecoration 继承自ItemDecoration。ok,我们试试如果自定义一个分割线。看一下DividerItemDecoration的setDrawable()方法。

/**
     * Sets the {@link Drawable} for this divider.
     *
     * @param drawable Drawable that should be used as a divider.
     */
    public void setDrawable(@NonNull Drawable drawable) {
        if (drawable == null) {
            throw new IllegalArgumentException("Drawable cannot be null.");
        }
        mDivider = drawable;
    }

明白了吧,先自定义一个drawable文件,如下:

image.png

给RecyclerView添加代码,如下:

image.png

2.1.2 itemDecoration 简单使用针对GridLayoutManager和StaggeredGridLayout

因为GridLayoutManager和StaggeredGridLayout的原理和方法差异不大, 我们就统一写一个了。 1.如果只是想简单实现我们可以在adapter的onCreateViewHolder()方法中设置View,如图:

image.png

2.2 如果想来一个稍微有难度的,可以尝试自定义一个ItemDecoration,那么就要 extends RecyclerView.ItemDecoration重写两个方法(其实一般有三个,我们这里用不到其中的一个onDrawOver):第一个getItemOffsets()此方法是针对每一个 ItemView,实际上RecyclerView 中的 ItemView 外面会包裹着一个矩形(outRect)。当outRect的左,右,上,下的内容都为0时,itemview和ontRect重叠你感觉只有一个item.类似:

image.png

其目的是控制矩形(outRect)与 ItemView的间隔,部分代码如下:

image.png

第二个方法:onDraw(),该方法配合前面的 getItemOffsets() 一起使用,在outRect矩形 与 ItemView的间隔区域 绘制内容,也就是在itemview的下面绘制了一个矩形的分割线,部分代码如下:

image.png

最后一步:给recyclerview设置自定义的分割线:

image.png

3.RecyclerView之实现滑动删除拖拽排序(首个可以固定)

3.1实现RecyclerView的滑动删除拖拽排序

滑动删除和拖拽必须用到ItemTouchHelper ,我们看它如何使用:

ItemTouchHelper  itemTouchHelper  = new ItemTouchHelper(new ItemTouchHelper.Callback());
itemTouchHelper.attachToRecyclerView(mRecyclerView); 

其创建的对象过程中要传一个ItemTouchHelper.CallBack(),它是ItemTouchHelper在拖拽中需要回调的方法,我们只需要在其对应返回的回调方法中处理自己的逻辑就好了,先看extends它需要重写的三个方法及作用。

image.png

针对getMovementFlags()方法如果是线性布局管理器有两个方向:上,下。但如果是网格布局管理器则有四个方向上,下,左,右,所以其方法要做判断是那种管理器,代码如下:

image.png

onMove()方法中的操作,注释都很明了,看不懂转行吧

这两个方法重写完,已经可以实现拖拽效果了,但为了美观我们要添加一个拖拽的背景,这就要用到另外两个方法:onSelectedChanged()和clearView(),代码如下:

image.png

然后就实现拖拽功能了

    ItemTouchHelper itemTouchHelper
                = new ItemTouchHelper(new RecyclerItemTouchHelperCallBack(mRecyclerViewAdapter));
        itemTouchHelper.attachToRecyclerView(mRecyclerView);

再然后我们使用第三个方法来实现滑动删除。

别忘了变动之前的getMovementFlags()。

image.png

这样我们就实现了滑动删除和拖拽移动功能,但别高兴太早,这代码仍然存在问题,你正常来讲网格布局应该不具备滑动删除才对,这怎么解决呢?通过有参构造来设置一个变量,在重写一个isItemViewSwipeEnabled()返回该boolean类型的值控制是否具备滑动删除即可。如图:

image.png

image.png

这样就是实现线性布局管理器和网格布局管理器区分对待,即:线性布局管理器拥有滑动删除和拖拽而网格布局管理器只拥有拖拽功能。

3.2实现首item固定功能

既然实现了item的拖拽和删除那么,首个固定就很简单了,我们继续在有参构造里添加一个boolean类型的变变量控制是否首个item固定,然后重写一个方法,如图:

image.png

image.png

所有item都被固定,然后

image.png

至此,首个item固定也就完成了。

4.RecyclerView之实现自定义动画

大家都看到了我们之前使用的是系统给我们提供的自带动画mRecyclerView.setItemAnimator(new DefaultItemAnimator());DafaultItemAnimator继承的是抽象类SimpleItemAnimator,SimpleItemAnimator主要对动画内部实现进行封装,通过抽象让我们更只关注于更具体的操作,我们定义一个类继承SimpleItemAnimator,然后里面主要有几个需要重写的方法。

  • void runPendingAnimations():当有动画需要执行时调用。
  • boolean isRunning():返回当前是否有动画正在运行。
  • boolean animateAdd():添加元素时调用,通常返回true。
  • boolean animateRemove():移除数据时调用。
  • boolean animateMove():列表项位置移动时调用。
  • boolean animateChange():列表项数据发生改变时调用。
  • void endAnimation():当某个动画需要被立即停止时调用,这里一般做视图的状态恢复。
  • void endAnimations() 作用和endAnimation()一样,区别是停止多个动画时调用。

具体就不说了,demo已上传github,代码戳我.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏androidBlog

使用ViewDragHelper打造属于自己的DragLayout(抽屉开关 )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details...

14720
来自专栏hotqin888的专栏

golang-fullcalendar,engineercms完善日历事件-支持拖曳drop,改变时间resize

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

20920
来自专栏Jaycekon

Phantomjs+Nodejs+Mysql数据抓取(2.抓取图片)

概要 这篇博客是在上一篇博客Phantomjs+Nodejs+Mysql数据抓取(1.抓取数据) http://blog.csdn.net/jokerko...

37650
来自专栏mukekeheart的iOS之旅

iOS学习—— UINavigationController的返回按钮与侧滑返回手势的研究

侧滑返回手势是从iOS7开始增加的一个返回操作,经历了两年时间估计iPhone用户大部分都已经忽略了屏幕左上角那个碍眼的back按钮了。之前在网上搜过有关侧滑...

1K60
来自专栏宋凯伦的技术小栈

Android - 页面返回上一页面的三种方式

  今年刚刚跳槽到了新公司,也开始转型做Android,由此开始Android的学习历程。   最近在解很多UI的bug,在解bug过程中,总结了在UI的实现过...

43980
来自专栏刘望舒

Android应用优化之流畅度实操

32730
来自专栏施炯的IoT开发专栏

《101 Windows Phone 7 Apps》读书笔记-Weight Tracker

课程内容 Ø Charts & Graphs     你平时关注自己的体重吗?Weight Tracker使得你可以随时跟踪自己的体重,并且提供几种体重发展趋...

20180
来自专栏狂码一生

MFC子窗口任务栏显示图标和主窗口最小化在系统托盘中显示图标

MFC子窗口任务栏显示图标很简单, 只需要在子窗口的初期化函数OnInitDialog()中添加ModifyStyleEx(WS_EX_TOOLWINDOW, ...

47680
来自专栏葡萄城控件技术团队

如何将GridViewEX升级到UWP(Universal Windows Platform)平台

引言 上一篇文章中,我们主要讲解了如何在保证GridView控件的用户体验基础上,扩展GridView生成GridViewEx控件,增加动态添加新分组功能等,本...

23180
来自专栏分享达人秀

SwipeRefreshLayout下拉刷新组件

在实际开发中,经常都会遇到下拉刷新、上拉加载更多的情形,这一期就一起来学习Android系统的SwipeRefreshLayout下拉刷新组件。 一、...

32270

扫码关注云+社区

领取腾讯云代金券