RecyclerView 的拖拽和长按变化Item的位置,设置左右滑动删除数据和滑动改变背景等

本文详细介绍如何使用ItemTouchHelper实现RecyclerView的拖拽排序、长按拖拽、左右滑动删除及滑动背景变化等功能。提供了自定义回调类MyItemTouchHelperCallback的实现方式,并解释了如何通过监听方向和状态来完成各项操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目地址:https://github.com/ChloeDimen/RecyclerviewDemo点击打开链接

1:想要实现RecyclerView 的拖拽和长按变化Item的位置,设置左右滑动删除数据和滑动改变背景的关键字:ItemTouchHelper

关键代码:

MyItemTouchHelperCallBack callback = new MyItemTouchHelperCallBack(adapter);
 itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(rl_data);

2:主要是实现MyItemTouchHelperCallback继承ItemTouchHelper.callback

public class MyItemTouchHelperCallBack extends ItemTouchHelper.Callback {
    private ItemTouchMoveListener mItemTouchMoveListener;

    public MyItemTouchHelperCallBack(ItemTouchMoveListener itemTouchMoveListener) {
        mItemTouchMoveListener = itemTouchMoveListener;
    }

    //callback回调监听先调用的,用来判断是什么动作,比如判断方向(意思就是我要监听那个方向的拖到)
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        //方向Up,down.left,right
        //ItemTouchHelper.UP,ItemTouchHelper.DOWN,ItemTouchHelper.LEFT,ItemTouchHelper.RIGHT
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;//添加上下滑动
        //int swipeFlags = 0;
        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//添加左右滑动
        int flags = makeMovementFlags(dragFlags, swipeFlags);


        return flags;
    }

    //当移动的时候回调的方法
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        if (viewHolder.getItemViewType() != target.getItemViewType()) {//条目布局不同,就不交换位置
            return false;
        }


        //adapter.notifyItemMoved(fromPositiontoPosition);改变拖拽item位置
        mItemTouchMoveListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return false;
    }

    //侧滑
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        //监听侧滑1:删除数据;2adapter.notifyItemRemoveposition        mItemTouchMoveListener.onItemRemove(viewHolder.getAdapterPosition());

    }

    //item改变状态
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {

        //判断选择状态,改变背景颜色
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(R.color.colorPrimary));

        }
        super.onSelectedChanged(viewHolder, actionState);

    }

    //状态背景颜色复原

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

        viewHolder.itemView.setBackgroundColor(Color.WHITE);

        super.clearView(recyclerView, viewHolder);
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        //dx,侧滑改变特效
if (actionState==ItemTouchHelper.ACTION_STATE_SWIPE){
    //设置透明度1-0
    float result = Math.abs(dX) / viewHolder.itemView.getWidth();
    viewHolder.itemView.setAlpha(result);

    //旋转
    viewHolder.itemView.setScaleX(result);
    viewHolder.itemView.setScaleY(result);

}

        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }

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


}

3:实现两个接口,分别拖拽效果和删除条目和移动条目的功能

public interface OnStartDragListener {
    /**
     * 该接口用于需要主动回调拖拽效果的
     * @param viewHolder
     */
    void onStartDrag(RecyclerView.ViewHolder viewHolder);

}
public interface ItemTouchMoveListener {
    /**
     * 当拖拽的时候回调
     * 可以在此方法实现拖拽条目,并实现刷新效果
     * @param fromPosition 从什么位置拖拽
     * @param toPosition 到什么位置
     * @return  是否执行
     */
    boolean onItemMove(int fromPosition, int toPosition);

    /**
     * 当条目被移除的回调
     * @param position
     * @return
     */
    boolean onItemRemove( int position);
}

4:adapter实现两个接口

public interface ItemTouchMoveListener {
    /**
     * 当拖拽的时候回调
     * 可以在此方法实现拖拽条目,并实现刷新效果
     * @param fromPosition 从什么位置拖拽
     * @param toPosition 到什么位置
     * @return  是否执行
     */
    boolean onItemMove(int fromPosition, int toPosition);

    /**
     * 当条目被移除的回调
     * @param position
     * @return
     */
    boolean onItemRemove( int position);
}

5:长按改变背景和拖拽改变位置效果

关键代码:

方向判断:

//callback回调监听先调用的,用来判断是什么动作,比如判断方向(意思就是我要监听那个方向的拖到)
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    //方向Up,down.left,right
    //ItemTouchHelper.UP,ItemTouchHelper.DOWN,ItemTouchHelper.LEFT,ItemTouchHelper.RIGHT
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;//添加上下滑动
    //int swipeFlags = 0;
    int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//添加左右滑动
    int flags = makeMovementFlags(dragFlags, swipeFlags);


    return flags;
}

长按:

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


改变位置

@Override
 public boolean onItemMove(int fromPosition, int toPosition) {
     //1:数据交换;  2:刷新

     Collections.swap(number,fromPosition,toPosition);
     notifyItemMoved(fromPosition,toPosition);
     return false;
 }


6:按下图片拖拽

关键代码:监听按下的状态

holder.iv_data.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            //传递触摸情况给谁,进行按下图片拖拽
            mListener.onStartDrag(holder);
        }

        return false;
    }
});

实现拖拽功能:

@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
    itemTouchHelper.startDrag(viewHolder);
}


7:左右滑动删除条目和透明度,旋转。。效果

关键代码:

//callback回调监听先调用的,用来判断是什么动作,比如判断方向(意思就是我要监听那个方向的拖到)
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    //方向Up,down.left,right
    //ItemTouchHelper.UP,ItemTouchHelper.DOWN,ItemTouchHelper.LEFT,ItemTouchHelper.RIGHT
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;//添加上下滑动
    //int swipeFlags = 0;
    int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//添加左右滑动
    int flags = makeMovementFlags(dragFlags, swipeFlags);


    return flags;
}
//侧滑
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    //监听侧滑1:删除数据;2adapter.notifyItemRemoveposition    mItemTouchMoveListener.onItemRemove(viewHolder.getAdapterPosition());

}

 @Override
public boolean onItemRemove(int position) {
    //1:删除数据;  2:刷新
    number.remove(position);
    notifyItemRemoved(position);
    return false;
}
 @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        //dx,侧滑改变特效
if (actionState==ItemTouchHelper.ACTION_STATE_SWIPE){
    //设置透明度1-0
    float result = Math.abs(dX) / viewHolder.itemView.getWidth();
    viewHolder.itemView.setAlpha(result);

    //旋转
    viewHolder.itemView.setScaleX(result);
    viewHolder.itemView.setScaleY(result);

}


8:item选中滑动效果(背景改变。。。。)

关键代码:

//item改变状态
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {

    //判断选择状态,改变背景颜色
    if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
        viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(R.color.colorPrimary));

    }
    super.onSelectedChanged(viewHolder, actionState);

}

//状态背景颜色复原

@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

    viewHolder.itemView.setBackgroundColor(Color.WHITE);

    super.clearView(recyclerView, viewHolder);
}




项目的文字说明很清晰了。

未完待续。。。。.















<think>我们有两个需求:1. 点击item内的拖拽图标触发拖拽;2. 按整个item触发拖拽。 使用ItemTouchHelper可以方便地实现RecyclerView拖拽滑动删除。但是,默认情况下,ItemTouchHelper支持按整个item触发拖拽,而点击某个特定图标触发拖拽则需要我们自己处理。 思路: 1. 对于按整个item触发拖拽:这是ItemTouchHelper的默认行为,我们只需要在Callback中设置setLongPressDragEnabled(true)即可。 2. 对于点击拖拽图标触发拖拽:我们需要在item拖拽图标上设置一个触摸或点击事件,当用户触摸该图标时,通知ItemTouchHelper开始拖拽。 具体步骤: a. 创建ItemTouchHelper.Callback的子类(例如MyItemTouchCallback)。 b. 在Callback中,重写getMovementFlags()方法,设置拖拽的方向(如上下左右)滑动删除的方向(如果需要)。 c. 重写onMove()方法处理拖拽过程中的位置交换。 d. 重写onSwiped()方法处理滑动删除(如果不需要滑动删除,可以忽略)。 e. 在Callback中,设置setLongPressDragEnabled(true)以启用拖拽。 f. 在RecyclerView的ViewHolder中,给拖拽图标设置OnTouchListener(或OnClickListener),并在触摸事件中调用ItemTouchHelper的startDrag()方法。 注意:为了在ViewHolder中调用ItemTouchHelper的startDrag(),我们需要将ItemTouchHelper实例传递给Adapter或ViewHolder。 实现步骤: 1. 创建ItemTouchHelper.Callback的子类: ```java public class MyItemTouchCallback extends ItemTouchHelper.Callback { private final OnItemMoveListener onItemMoveListener; // 用于回调拖拽滑动事件 public MyItemTouchCallback(OnItemMoveListener listener) { this.onItemMoveListener = listener; } @Override public boolean isLongPressDragEnabled() { // 启用拖拽 return true; } @Override public boolean isItemViewSwipeEnabled() { // 禁用滑动删除(如果需要可以开启) return false; } @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { // 设置拖拽方向为上下左右(根据需求调整) int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; int swipeFlags = 0; // 如果不支持滑动删除设置为0 return makeMovementFlags(dragFlags, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { // 当拖拽时调用,通知Adapter移动数据 if (onItemMoveListener != null) { return onItemMoveListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); } return false; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { // 滑动删除,这里不需要实现 } } ``` 2. 定义OnItemMoveListener接口,用于回调拖拽事件: ```java public interface OnItemMoveListener { boolean onItemMove(int fromPosition, int toPosition); } ``` 3. 在RecyclerView.Adapter中实现OnItemMoveListener接口,并在onItemMove()中交换数据并刷新视图。 4. 在ViewHolder中,给拖拽图标设置触摸事件(注意:这里使用OnTouchListener,因为我们需要在触摸事件中触发拖拽,这样用户体验更好): ```java public class MyViewHolder extends RecyclerView.ViewHolder { ImageView dragHandle; // 拖拽图标 public MyViewHolder(View itemView) { super(itemView); dragHandle = itemView.findViewById(R.id.drag_handle); // 设置触摸监听器 dragHandle.setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_DOWN) { // 当按下时,开始拖拽 if (itemTouchHelper != null) { itemTouchHelper.startDrag(this); } return true; } return false; }); } } ``` 注意:ViewHolder需要持有ItemTouchHelper的引用(例如通过构造方法传入,或者通过Adapter设置)。这里我们假设ViewHolder中有一个itemTouchHelper成员变量。 5. 在Activity或Fragment中设置RecyclerViewItemTouchHelper: ```java RecyclerView recyclerView = findViewById(R.id.recyclerView); MyAdapter adapter = new MyAdapter(); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 创建Callback MyItemTouchCallback callback = new MyItemTouchCallback(adapter); ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback); itemTouchHelper.attachToRecyclerView(recyclerView); // 将itemTouchHelper传递给Adapter,以便Adapter在创建ViewHolder时传递给ViewHolder adapter.setItemTouchHelper(itemTouchHelper); ``` 6. 在Adapter中,设置ItemTouchHelper给ViewHolder: ```java public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> implements OnItemMoveListener { private ItemTouchHelper itemTouchHelper; public void setItemTouchHelper(ItemTouchHelper itemTouchHelper) { this.itemTouchHelper = itemTouchHelper; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false); // 在创建ViewHolder时将itemTouchHelper传递过去 return new MyViewHolder(view, itemTouchHelper); } // ... 其他方法 @Override public boolean onItemMove(int fromPosition, int toPosition) { // 交换数据 Collections.swap(dataList, fromPosition, toPosition); notifyItemMoved(fromPosition, toPosition); return true; } } ``` 7. 修改ViewHolder的构造方法,接收ItemTouchHelper: ```java public MyViewHolder(View itemView, ItemTouchHelper itemTouchHelper) { super(itemView); this.itemTouchHelper = itemTouchHelper; // ... 初始化其他视图 } ``` 这样,我们就实现了两种触发拖拽的方式: - 按整个item(由ItemTouchHelper自动处理) - 点击拖拽图标(通过设置OnTouchListener并调用startDrag) 注意:在点击图标拖拽时,可能会有冲突。但是,由于拖拽按整个item,而图标拖拽是按下图标,所以一般不会冲突。如果出现冲突,可以在Callback中通过条件控制。 另外,如果不需要按整个item触发拖拽,可以在Callback的isLongPressDragEnabled()中返回false,这样只允许通过图标拖拽。 参考引用[1][2]提供了ItemTouchHelper的基本使用自定义拖拽的实现,我们可以在此基础上扩展。 以上代码为示例,实际使用中需要根据项目情况调整。 相关问题: 1. 如何实现RecyclerView滑动删除功能? 2. ItemTouchHelper.Callback中还有哪些可以重写的方法用于自定义拖拽滑动效果? 3. 如何限制拖拽只在同一类型的item之间进行?</think>### 实现 RecyclerView 拖拽功能(点击图标+按触发) 在 Android 中实现 RecyclerView拖拽功能需要结合 `ItemTouchHelper` 自定义逻辑。以下是完整实现步骤: --- #### 1. **创建 ItemTouchHelper.Callback** ```java public class DragCallback extends ItemTouchHelper.Callback { private final OnItemMoveListener moveListener; public DragCallback(OnItemMoveListener listener) { this.moveListener = listener; } @Override public boolean isLongPressDragEnabled() { // 启用拖拽 return true; } @Override public boolean isItemViewSwipeEnabled() { // 禁用侧滑删除 return false; } @Override public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { // 设置拖拽方向(上下左右) int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; return makeMovementFlags(dragFlags, 0); } @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder source, @NonNull RecyclerView.ViewHolder target) { // 通知 Adapter 数据交换 moveListener.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {} } // 数据交换接口 public interface OnItemMoveListener { void onItemMove(int fromPosition, int toPosition); } ``` --- #### 2. **在 Adapter 中实现拖拽逻辑** ```java public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> implements OnItemMoveListener { private final List<Item> dataList = new ArrayList<>(); private ItemTouchHelper touchHelper; // 用于触发拖拽 @Override public void onItemMove(int fromPos, int toPos) { // 交换数据位置 Collections.swap(dataList, fromPos, toPos); notifyItemMoved(fromPos, toPos); } // 设置 ItemTouchHelper(从 Activity 传入) public void setTouchHelper(ItemTouchHelper helper) { this.touchHelper = helper; } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { // 设置拖拽图标的点击事件 holder.dragIcon.setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_DOWN) { // 点击图标触发拖拽 touchHelper.startDrag(holder); return true; } return false; }); } } ``` --- #### 3. **在 Activity/Fragment 中初始化** ```java // 初始化 RecyclerView RecyclerView recyclerView = findViewById(R.id.recyclerView); MyAdapter adapter = new MyAdapter(); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 创建并绑定 ItemTouchHelper DragCallback callback = new DragCallback(adapter); ItemTouchHelper touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(recyclerView); // 将 touchHelper 传递给 Adapter(用于图标拖拽) adapter.setTouchHelper(touchHelper); ``` --- #### 4. **ViewHolder 布局示例 (item_layout.xml)** ```xml <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <!-- 内容区域 --> <TextView android:id="@+id/tvContent" android:layout_width="match_parent" android:layout_height="56dp"/> <!-- 拖拽图标(右侧) --> <ImageView android:id="@+id/ivDrag" android:layout_width="24dp" android:layout_height="24dp" android:layout_gravity="right|center_vertical" android:src="@drawable/ic_drag" android:padding="8dp"/> </FrameLayout> ``` --- #### 关键点说明: 1. **拖拽** 通过 `isLongPressDragEnabled()` 返回 `true` 自动启用 2. **图标点击拖拽** 在 ViewHolder 中为拖拽图标设置 `OnTouchListener`,通过 `touchHelper.startDrag()` 手动触发 3. **数据更新** 在 `onItemMove()` 中交换数据并调用 `notifyItemMoved()` 4. **滑动禁用** `isItemViewSwipeEnabled()` 返回 `false` 关闭侧滑 > 引用说明:本实现基于 Android 官方 `ItemTouchHelper` 机制[^1],并扩展了点击图标触发拖拽的功能,解决了拖拽的交互限制[^2]。 --- ### 相关问题 1. 如何实现 RecyclerView 拖拽时的视觉反馈(如阴影效果)? 2. 如何限制拖拽只能在特定类型的 Item 之间进行? 3. 如何实现拖拽过程中的数据自动保存? 4. 如何处理嵌套 RecyclerView拖拽事件冲突?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值