[Android]RecycleView的item用法

RecyclerView 是 Android 提供的一个强大的列表控件,用来显示大量数据。

RecyclerView 的主要特点

1. 高性能的视图复用机制

Recycle就是循环的意思,那么recycleview的特点也很鲜明了,它只会创建出在屏幕内和一定缓存的itemview,当view滑出屏幕时,不会销毁重建,而是复用旧的view,可以极高的提高性能;

2. 高度可定制

可以添加分割线、动画、拖拽、滑动删除;

3. 支持多种布局

支持线性、网格、瀑布流等布局实现;

子项的点击事件和长按点击事件

总体思路:因为我们在适配器的viewholder中可以拿到每个子项的view的,此时可以设置监听调用Onclick方法或者OnLongClick方法,然后通过接口回调的方式在RecycleView中设置回调的逻辑处理;

那么为什么要通过接口回调的方式呢?是因为适配器的任务就是绑定数据后显示UI,它不应该决定点击事件后的逻辑处理,所以在适配器中实现子项的监听,但是真正的实现我们放到Activity或者Fragment中,这样有利于解耦;

接下来看看具体的实现:

在适配器中:

Android 复制代码
private OnItemClickListener onItemClickListener;
public interface OnItemClickListener{
    void onItemClick(cityadapt cityadapt,int position);
    void onItemLongClick(cityadapt cityadapt,int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
    this.onItemClickListener = onItemClickListener;
}
//实现接口,使得调用适配器中的Onclick的方法,然后再进行接口回调
public class cityviewholder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public cityviewholder(@NonNull View itemView) {
    super(itemView);
     itemView.setOnClickListener(this);
}

    @Override
    public void onClick(View view) {
        if(onItemClickListener!= null){
            onItemClickListener.onItemClick(cityadapt.this,getAdapterPosition());
        }
    }

    @Override
    public boolean onLongClick(View view) {
        return true;
    }
}

在实现类中

Android 复制代码
cityadapt1.setOnItemClickListener(new cityadapt.OnItemClickListener() {
    @Override
    public void onItemClick(cityadapt cityadapt, int position) {
        viewPager2.setCurrentItem(position,true);
    }

    @Override
    public void onItemLongClick(cityadapt cityadapt, int position) {

    }
});

在进行子项的删除和拖动的学习之前,得先了解一个类:ItemTouchHelper

ItemTouchHelper

  • ItemTouchHelper 是 Android 官方提供的一个 RecyclerView 辅助类

  • 它通过 监听手势事件 ,帮助我们轻松实现:

    Item 拖动(上下或左右移动)

    Item 滑动(左滑/右滑删除,或执行其他操作)

  • 不需要自己去写复杂的手势检测逻辑。

我理解的本质也是接口回调,我们只定义接口的实现,然后作为构造方法的参数传入ItemTouchHelper的实例中,最后与RecycleView绑定;

在这里我们定义回调后的实现,比如允许滑动的方向等等;

Android 复制代码
ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
}

然后通过ItemTouchHelper的实例传入,使得后续做出自定义的逻辑判断和反应等;

Android 复制代码
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);

最后通过attachToRecyclerView与recycleview绑定,binding.recyCity是recycleview的实例;

Android 复制代码
itemTouchHelper.attachToRecyclerView(binding.recyCity);

ItemTouchHelper.Callback中有必须实现的三个抽象方法:

  • getMovementFlags():用来指定支持的拖拽和滑动方向

  • onMove():拖拽时回调(交换两个 item 的位置)

  • onSwiped():侧滑时回调(比如删除 item)

在本模块中介绍一下`getMovementFlags()

Android 复制代码
//规定可以滑动的方向
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
    int position = viewHolder.getAdapterPosition();
    if(position == 0){
        return 0;
    }
    int ver = 0;
    int hor = ItemTouchHelper.LEFT;
    return makeMovementFlags(ver,hor);
}
  • 最后返回一个方法makeMovementFlags(ver,hor),参数有两个,第一个是关于允许上下滑动或拖拽的,第二个是关于上下的;
Android 复制代码
int position = viewHolder.getAdapterPosition();
if(position == 0){
    return 0;
}

这里这么写得到当前滑动或者拖动的位置,如果这个是recycleview中第一个的话,就返回0,意味着不允许滑动或者拖拽;

  • ItemTouchHelper.LEFTItemTouchHelper.LEFTItemTouchHelper 里定义的一个常量,代表滑动(swipe)时允许的方向之一;

剩余的其他:

ItemTouchHelper.UP // 向上拖动

ItemTouchHelper.DOWN // 向下拖动

ItemTouchHelper.LEFT // 向左滑动

ItemTouchHelper.RIGHT // 向右滑动

子项的删除事件

ItemTouchHelper的基础上,我们还需重写一个方法:

Android 复制代码
//是否允许滑动移除
 @Override
 public boolean isItemViewSwipeEnabled() {
     return true;
 }

然后在ItemTouchHelper中的onSwiped方法内规定逻辑;

Android 复制代码
           //规定左滑后的逻辑
            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
                int i = viewHolder.getAdapterPosition();
                if(i != 0){
                    cityadapt1.getData().remove(i);
                    cityadapt1.notifyItemRemoved(i);
//                MainActivity.deleteFragment(i);
                    addtomainweather.deleteFragment(i);
                }
            }

里面有三个方法:

  • cityadapt1.getData().remove(i) : 把适配器中持有的数据源里对应的 item 移除;

  • cityadapt1.notifyItemRemoved(i):触发删除的动画;

  • addtomainweather.deleteFragment(i):通过接口回调的方式,自定义实现删除的逻辑;

当然我们也可以定义删除的动画

子项删除事件的动画效果

代码如下:

Android 复制代码
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
        View view = viewHolder.itemView;
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        if(dX < 0){
           c.drawRect((float) view.getRight()+dX,(float) view.getTop(),(float) view.getRight(),(float) view.getBottom(),paint);
            Bitmap icon = BitmapFactory.decodeResource(recyclerView.getContext().getResources(),R.drawable.deletecity);
            int iconmargin =( view.getHeight() - icon.getHeight())/2;
            int top = view.getTop()+iconmargin;
            int bottom = top + icon.getHeight();
            int left = view.getRight() - iconmargin - icon.getWidth();
            int right =  view.getRight() - iconmargin;
            c.drawBitmap(icon,null,new Rect(left,top,right,bottom),null);
        }
    }
}

这个方法是 ItemTouchHelper.Callback 提供的 onChildDraw ,用来在 拖动/滑动时绘制额外的 UI 效果(比如背景、按钮、图标;

先看看这个方法对应的参数:

@NonNull Canvas c, // 画布

@NonNull RecyclerView recyclerView, // 当前的 RecyclerView

@NonNull RecyclerView.ViewHolder viewHolder, // 当前正在交互的 item

float dX, // X 方向的位移

float dY, // Y 方向的位移

int actionState, // 当前手势状态(滑动/拖动)

boolean isCurrentlyActive // 手指是否还在按住 item

代码中的部分说明:

actionState == ItemTouchHelper.ACTION_STATE_SWIPE是如果手势是滑动的话;

其他的滑动:

  • ItemTouchHelper.ACTION_STATE_IDLE → 没有操作

  • ItemTouchHelper.ACTION_STATE_DRAG → 拖动中

View view = viewHolder.itemView;获得当前的item;

c.drawRect((float) view.getRight()+dX,(float) view.getTop(),(float) view.getRight(),(float) view.getBottom(),paint); :里面有五个参数,分别是规定滑动后矩形的左边界,矩形的上边界,矩形的右边界,矩形的下边界,以及绘制的颜色/样式;

Bitmap icon = BitmapFactory.decodeResource(recyclerView.getContext().getResources(),R.drawable.deletecity);``recyclerView.getContext().getResources(),得到文件资源管理器,得到对应的图片等;
BitmapFactory.decodeResource(Resources res, int id)BitmapFactory是一个解码工具类,这个方法会读取资源文件,并转成内存中的 Bitmap 对象

c.drawBitmap(icon,null,new Rect(left,top,right,bottom),null);四个参数分别代表:设置到画布上的bitmap对象,源区域(null代表设置整张图片),以及你要放置的位置,设置透明度等;

子项的拖动事件

重写此方法:

Android 复制代码
//是否允许长按拖拽
@Override
public boolean isLongPressDragEnabled() {
    return true;
}

此处跟删除的逻辑差不多,解释放在注释中,可自行观看;

Android 复制代码
            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            //返回当前正在拖动的适配器中的数据索引
                  int i = viewHolder.getAdapterPosition();
                  //返回目标适配器中的数据索引
                  int j = target.getAdapterPosition();
                  //把适配器中持有的数据源里对应的 item 交换;
                  Collections.swap(cityadapt1.getData(),i,j);
                  //刷新item移动动画
                  cityadapt1.notifyItemMoved(i,j);
                  addtomainweather.swapFragment(i,j);
                  return true;
            }

            

这样我们就可以实现子项的点击事件,删除,拖动啦;

--未完待续--

相关推荐
恋猫de小郭15 小时前
Android 发布全新性能分析器,实用性和性能大升级
android·前端·flutter
Kapaseker15 小时前
为什么 Java 的数组需要 new 出来
android·java·kotlin
黄林晴15 小时前
颠覆开发!Google AI Studio 一句话生成原生 Android App
android·google io
恋猫de小郭15 小时前
Flutter 3.44 发布啦,超级大版本更新!!!
android·flutter·ios
zb2006412015 小时前
Laravel10.x重磅升级:新特性全解析
android
2601_9574188016 小时前
深入解析Android相机有线连接:PTP与MTP协议栈实现原理与实践
android·数码相机·智能手机
努力努力再努力wz16 小时前
【QT入门系列】QWidget 六大常用属性详解:windowOpacity、cursor、font、focus、toolTip 与 styleSheet
android·开发语言·数据结构·c++·qt·mysql·算法
撩得Android一次心动16 小时前
C语言基础笔记3【个人用】
android·c语言·开发语言·笔记
小离a_a16 小时前
uniapp小程序封装圆环显示比例数据
android·小程序·uni-app
三少爷的鞋16 小时前
Android 面试系列:runBlocking 到底该在哪用?
android