• RecycleView的一些使用


    依赖

    在项目的gradle文件中引入一下这个包

     implementation 'androidx.recyclerview:recyclerview:1.2.0'
    
    • 1

    基本使用

    Activity中代码

    //首先要找到该组件(必做)
    RecyclerView recyclerView = findViewById(R.id.recycleView);
    //准备要展示的数据源(必做)
    photoBeanList =PhotoUtil.getPhotosFromFiles(MainActivity.this);
    //设置LayoutManager(必做),这里设置网格布局
    //设置 layoutManager 这个是Recycleview必须的 不然Recycleview 的内容不会显示。
    //RecyclView提供了 LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager 3 个系统的。当然也可以继承LayoutManager自定义
    recyclerView.setLayoutManager(newGridLayoutManager(MainActivity.this, 3));
    //下面是线性 layoutManager的用法,后面还会详细介绍
    //LinearLayoutManager layoutManager = new //LinearLayoutManager(this);
    //如果将 orientation 设置为 HORIZONTAL 可以轻易的实现横向的 listview 效果       //layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    //recyclerView.setLayoutManager(layoutManager);
                               
    //创建适配器对象(必做)
    adapter = new PhotoAdapter(MainActivity.this, photoBeanList);
    //设置适配器(必做)
    recyclerView.setAdapter(adapter);
    
    //设置动画(可选,在增加或删除条目时的动画)
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    //使用自带的分割线
    recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL));
    //自定义分割(可选,需要继承RecyclerView.ItemDecoration类)
    recyclerView.addItemDecoration(new mydivider());
                              
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Adapter 对应代码
    基本的步骤为:

    1. RecyclerView新增适配器PhotoAdapter ,并让其继承于RecyclerView.Adapter,把泛型指定为PhotoAdapter .ViewHolder
      定义内部类ViewHolder,并继承RecyclerView.ViewHolder。传入的View参数通常是RecyclerView子项的最外层布局。

    2. PhotoAdapter 构造函数,用于把要展示的数据源传入,并赋予值给全局变量dataList

    3. PhotoAdapter 继承RecyclerView.Adapter。因为必须重写onCreateViewHolder(),onBindViewHolder()getItemCount()三个方法

    • onCreateViewHolder()用于创建ViewHolder实例,并把加载的布局传入到构造函数去,再把ViewHolder实例返回。
    • onBindViewHolder()则是用于对子项的数据进行赋值,会在每个子项被滚动到屏幕内时执行。position得到当前项的photo实例。
    • getItemCount()返回RecyclerView的子项数目。
    /**
     * @ClassName PhotoAdapter
     * @Description 图片数据适配器
     * @Author Yu
     * @Date 2022/6/17 10:53
     * @Version 1.0
     **/
     //此处 继承的 RecyclerView.Adapter 中的泛型指定为我们自定义的 ViewHolder的类型(static class ViewHolder extends RecyclerView.ViewHolder)
    public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.ViewHolder>{
        private List<PhotoBean> dataList;
        private BaseActivity activity;
        private PhotoBean bean;
        private int selectedIndex=-1;//用于记录当前选中的索引
    
        public void setSelectedIndex(int position) {
            this.selectedIndex = position;
        }
    
        public PhotoAdapter (BaseActivity activity,List<PhotoBean> dataList){
            this.dataList=dataList;
            this.activity=activity;
        }
        /** 创建 viewHolder 将 xml 传递给ViewHolder */
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.photo_item, parent, false);
            ViewHolder holder = new ViewHolder(view);
            holder.item_photo.setOnLongClickListener(v->{
                int position = holder.getAdapterPosition();
                setSelectedIndex(position);//声明并赋值一个当前选中的索引
                AlertDialog.Builder builder = new AlertDialog.Builder(activity);//dialog
                builder.setTitle("温馨提示");
                builder.setMessage("真的要删除吗?删除后不可恢复");
                builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {//确定对应的回执事件
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        int i = PhotoUtil.deleteFromFile(activity, dataList.get(selectedIndex).getpId());//从数据库中删除
                        if (i>0){
                            Toast.makeText(activity, "删除成功!", Toast.LENGTH_SHORT).show();
                            dataList.remove(selectedIndex);//从列表中删除
                            notifyItemRemoved(selectedIndex);
                            //refreshList(dataList);//刷新视图
                        }else{
                            Toast.makeText(activity, "删除失败!", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
                builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
    
                    }
                });
                builder.create().show();
                return true;
            });
            return holder;
        }
    /** 这里是设置item操作的地方 */
        @Override
        public void onBindViewHolder(@NonNull PhotoAdapter.ViewHolder holder, int position) {
            bean=dataList.get(position);
            Glide.with(activity)
                    .load(bean.getUrl())
                    .error(R.drawable.picloaderror)
                    .centerCrop()
                    .into(holder.item_photo);
    
            holder.item_photo.setOnClickListener(v->{//点击任意一张图片对应事件
                Intent intent = new Intent(activity, PhotoViewPagesActivity.class);
                intent.putParcelableArrayListExtra("DATALIST",(ArrayList<PhotoBean>) dataList);//传递数据
                intent.putExtra("CURRENTPOSITION",position);
                activity.overridePendingTransition(R.anim.scale_in, R.anim.scale_out);
                activity.startActivity(intent);
            });
        }
     /** 跟 BaseAdapter 的 getCount 作用一样。返回 */
        @Override
        public int getItemCount() {
            return dataList == null ? 0 : dataList.size();
        }
     /** ViewHolder类,这个类用来初始化控件 */
        static class ViewHolder extends RecyclerView.ViewHolder {
            private ImageView item_photo;
    
            ViewHolder(@NonNull View itemView) {
                super(itemView);
                item_photo=itemView.findViewById(R.id.iv_photo_item);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    LayoutManager 布局管理器

    LayoutManager用于指定RecyclerView的布局方式。系统也为我们提供了三个实现类,同时提供了一个可供用户自定义布局管理抽象类RecycleView.LayoutManager

    LinearLayoutManager:线性布局, 支持纵向、横向(可以很轻松的实现横向listview的效果)

    mRecyclerView.layoutManager = LinearLayoutManager(context上下文,显示方向,是否反转显示)
    
    • 1

    GridLayoutManager:网格布局,线性布局是单行显示,网格布局可以设置并行显示的列数(竖直方向显示)

    mRecyclerView.layoutManager = GridLayoutManager(上下文,显示行(列)数,显示方向,是否逆转显示)
    
    • 1

    StaggeredGridLayoutManage:瀑布布局,类似淘宝商品展示的效果,可以交错显示

    mRecyclerView.layoutManager = StaggeredGridLayoutManager(显示行(列)数,显示方向)
    
    • 1

    ItemDecoration 分割线

     recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
    
    • 1

    recycleView 提供了一个分割线类。 VERTICAL表示分割线在item的底部,如果改为HORIZONTAL 则分割线在item的右侧。这个Decoration类还可以设置 setDrawable()要实现更加酷炫的分割线效果需要继承ItemDecoratio类 进行自定义。
    ItemDecoratio类 中包含以下三个方法:

    • onDraw()方法在drawChildren之前调用
    • onDrawOver()方法在drawChildren之后调用
    • getItemOffsets()方法中可以利用outRect为每个item设置一定的偏移量以实现给RecycleView的item添加边距

    onDrawonDrawOver方法针对的是RecycleView本身。所以,在这两个方法中要遍历屏幕上可见的item,分别计算和绘制分割线。绘制完成后onDraw在item下面,item在中间,onDrawOver是可以盖住onDraw和item的

        @Override
        public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
            super.onDraw(c, parent, state);
            // 这个方法得到的 RecycleView 中 child view 的个数,也就是屏幕中显示的item的个数。并不是adapter中数据源的大小
            int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i ++) {
                View child = parent.getChildAt(i);
                int left = child.getLeft() + mDividerW / 2;
                int right = child.getRight() + 60;
                int top = child.getBottom() - mDividerW;
                int bottom = child.getBottom() + mDividerW / 2;
                c.drawRect(left, top, right, bottom, paint);
                c.drawText("onDraw", (right)/2, bottom - 40, paintText);
            }
        }
    
        @Override
        public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
            super.onDrawOver(c, parent, state);
            int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i ++) {
                View child = parent.getChildAt(i);
                int left = child.getLeft() + mDividerW / 2;
                int right = child.getRight() + 60;
                int top = child.getTop() - mDividerW / 2;
                int bottom = child.getTop() + mDividerW / 2;
                c.drawRect(left, top, right, bottom, paintOver);
                c.drawText("onDrawOver", (right)/2, bottom - 40, paintText);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    getItemOffsets方法针对的是每一个item

    //这里我们设置item(left,top,right,bottom)四周的间隔分别为(20, 20, 0, 20)
    outRect.set(20, 20, 0, 20);
    
    • 1
    • 2

    当我们设置了recyclerView.addItemDecoration(官方分割线类/自定义类) 后,当recycleView绘制的时候,会绘制我们设置的 Decoration。

    ItemAnimator 动画

    RecycleView设置动画,只要调用recyclerView.setItemAnimator(new DefaultItemAnimator());方法即可,这也是一个抽象类,我们可以继承这个类自定义动画,同时系统也为我们提供了一个默认动画DefaultItemAnimator。

    这里要注意呈现ItemAnimator需要调用RecycleView.AdapternotifyItemRemoved(position)/notifyItemInserted();/notifyItemChanged等方法,调用notifyDataSetChanged()方法动画是无效的。

    注意事项:实际增删操作过程中position不会自动增加,导致数据错位的问题,所以,当我们需要使用这些特效方法的时候,必须要重新刷新一遍数据,纠正position。或者用viewHolder.getAdapterPosition()获取我们需要的position进行数据操作

    • notifyDataSetChanged();列表全局刷新,给recyleview添加增删条目的动画时,调用这种刷新方法时无法生效的

    • notifyItemInserted(int position) 列表position位置添加一条数据时可以调用,伴有动画效果

    • notifyItemRemoved(int position) 列表position位置移除一条数据时调用,伴有动画效果

    • notifyItemMoved(int fromPosition, int toPosition) 列表fromPosition位置的数据移到toPosition位置时调用,伴有动画效果

    • notifyItemRangeChanged(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项进行数据刷新

    • notifyItemRangeInserted(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项批量添加数据时调用,伴有动画效果

    • notifyItemRangeRemoved(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项批量删除数据时调用,伴有动画效果

    RecycleView的优化策略

    • 不要在onBindViewHolder中设置监听器,在onCreateViewHolder中设置监听器
    • 使用DiffUtilRecyclerView.setHasFixedSize()方法
    • 使用 LinearLayoutManager.setInitialPrefetchitemCount()方法
    • 多个RectclerView共用RecycledViewPool.
  • 相关阅读:
    CSS——前端笔记
    elementui的el-dialog组件与el-tabs同时用导致浏览器卡死的原因解决
    Java的对象克隆
    1、Flutter移动端App实战教程【环境配置、模拟器配置】
    按照前序输入创建二叉树并以前序遍历二叉树
    【Python实战】再分享一款商品秒杀小工具,我已经把压箱底的宝贝拿出来啦~
    国内代码托管平台Gitee(码云)的入门使用
    【C++和数据结构】模拟实现哈希表和unordered_set与unordered_map
    SCI论文投稿经验分享,建议收藏!
    森林监测VR虚拟情景再现系统更便利
  • 原文地址:https://blog.csdn.net/weixin_44524687/article/details/125431176