Android 事件分发 系列文章目录

【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )
【Android 事件分发】事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )
【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 一 )
【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 二 )
【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 )
【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 四 | View 事件传递机制 )
【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 )
【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 六 )
【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 七 )

【Android 事件分发】ItemTouchHelper 简介 ( 拖动/滑动事件 | ItemTouchHelper.Callback 回调 )
【Android 事件分发】ItemTouchHelper 实现侧滑删除 ( 设置滑动方向 | 启用滑动操作 | 滑动距离判定 | 滑动速度判定 | 设置动画时间 | 设置侧滑触发操作 )
【Android 事件分发】ItemTouchHelper 实现拖动排序 ( 设置滑动方向 | 启启用长按拖动功能 | 拖动距离判定 | 设置拖动触发操作 )


文章目录

  • Android 事件分发 系列文章目录
  • 一、ItemTouchHelper.Callback 配置侧滑删除
    • 1、设置移动标志 ( 拖动/滑动 )
    • 2、启用长按拖动功能
    • 3、拖动距离判定设置
    • 4、设置拖动排序触发操作
    • 5、RecyclerView.Adapter 适配器中的交换排序操作
  • 三、完整代码实现
    • 1、主界面
    • 2、ItemTouchHelper.Callback 回调类
    • 3、执行效果
  • 三、博客资源

一、ItemTouchHelper.Callback 配置侧滑删除


1、设置移动标志 ( 拖动/滑动 )

重写 ItemTouchHelper.Callback 的 getMovementFlags 方法 , 在该方法中设置滑动/拖动标志位 ;

滑动 / 拖动 标志 , 可使用 ItemTouchHelper.UP , ItemTouchHelper.DOWN , ItemTouchHelper.LEFT , ItemTouchHelper.RIGHT , 进行或操作得到 ;

        // 设置拖动方向, 此处设置上下拖动事件int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;// 设置滑动方向, 此处设置左右侧滑事件int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

再将 拖动标志 和 滑动标志 传入 makeMovementFlags 方法 , 得到一个移动标志位 , 作为 getMovementFlags 方法的返回值 ;

makeMovementFlags(dragFlags, swipeFlags);
public class Callback extends ItemTouchHelper.Callback {/*** 设置上下左右动作* 只有在此处打开了指定方向的设置 , 才可以应用具体方向的拖动* @param recyclerView* @param viewHolder* @return*/@Overridepublic int getMovementFlags(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder viewHolder) {// 设置拖动方向, 此处设置上下拖动事件int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;// 设置滑动方向, 此处设置左右侧滑事件int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;// 应用 拖动 和 滑动 设置return makeMovementFlags(dragFlags, swipeFlags);}
}

2、启用长按拖动功能

重写 ItemTouchHelper.Callback 的 isLongPressDragEnabled 方法 , 将该方法返回值设置为 true , 启用长按拖动功能 ;

public class Callback extends ItemTouchHelper.Callback {/*** 是否启用长按拖动功能* @return*/@Overridepublic boolean isLongPressDragEnabled() {return true;}
}

3、拖动距离判定设置

重写 ItemTouchHelper.Callback 的 getMoveThreshold 方法 , 设置用户的拖动距离 , 组件在宽度 / 高度 上移动超过该比例 , 就认为拖动触发, 执行拖动相关操作 ;
设置的是比例值, 返回值为 0.9 , 就意味着滑动宽度/高度的 0.9 倍, 才触发拖动排序 onMove 方法 ;

public class Callback extends ItemTouchHelper.Callback {/*** 拖动幅度设置* 组件在宽度 / 高度 上移动超过该比例 , 就认为拖动触发, 执行拖动相关操作* @param viewHolder* @return*/@Overridepublic float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {// 该案例中, 拖动操作只能上下进行// 拖动超过条目组件高度超过 0.9 倍, 即可触发拖动操作return 0.9f;}
}

上面案例中设置的拖动幅度是 0.9f , 在 getMovementFlags 方法中设置的拖动方向是上下拖动 , 因此在该案例中 , 上下拖动的幅度必须要在 0.9 倍高度 , 拖动排序功能才能生效 ;

下面的操作中 , 拖动的幅度没有达到 条目组件 高度的 0.9 倍 , 拖动排序功能没有触发 ;

下面的操作中 , 拖动的幅度超过了 条目组件 高度的 0.9 倍 , 拖动排序功能 触发 ;

4、设置拖动排序触发操作

重写 ItemTouchHelper.Callback 的 onMove 方法 , 用户拖动操作定成功后 , 会调用该方法 , 如果拖动判定不成功 , 则不会调用该方法 ;

onMove 方法的 第 222 参数 , 是拖动的条目索引 ; 第 333 参数 , 是拖动后的的位置条目 ;
可以通过调用 RecyclerView.ViewHolder 的 getAdapterPosition 方法 , 可以获取该条目的索引值 ;

public class Callback extends ItemTouchHelper.Callback {/*** 监听滑动事件* 滑动分 水平 / 垂直 两个方向* @param recyclerView* @param viewHolder* @param target* @return*/@Overridepublic boolean onMove(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder viewHolder,@NonNull RecyclerView.ViewHolder target) {// 拖动后交换数据, 该方法中交换 Adapter 中的数据, 并刷新界面Log.i(TAG, "触发拖动交换条目");mAdapter.changeItem(viewHolder.getAdapterPosition(), target.getAdapterPosition());return true;}
}

5、RecyclerView.Adapter 适配器中的交换排序操作

删除数据列表中的元素 , 并调用 notifyItemRemoved 触发删除动画 ;

    public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {/*** 交换条目元素* @param srcPosition* @param dstPosition*/public void changeItem(int srcPosition, int dstPosition) {// 交换集合中两个元素位置Collections.swap(names, srcPosition, dstPosition);// 刷新界面显示notifyItemMoved(srcPosition, dstPosition);}}

三、完整代码实现


1、主界面

package kim.hsl.recyclerview;import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;import java.util.ArrayList;
import java.util.Collections;public class MainActivity extends AppCompatActivity {/*** 数据源*/private ArrayList<String> names = new ArrayList<String>();/*** 当前的 RecyclerView 列表*/private RecyclerView recycler_view;/*** 布局管理器*/private LinearLayoutManager layoutManager;/*** 适配器*/private Adapter adapter;/*** 添加拖动处理*/private ItemTouchHelper mItemTouchHelper;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 初始化数据initData();//1 . 从布局中获取 RecyclerViewrecycler_view = findViewById(R.id.recycler_view);//2 . 创建并设置布局管理器//创建布局管理器layoutManager = new LinearLayoutManager(this,RecyclerView.VERTICAL,false);//设置布局管理器recycler_view.setLayoutManager(layoutManager);// 设置边距recycler_view.addItemDecoration(new ItemDecoration());//3 . 创建并设置列表适配器adapter = new Adapter();recycler_view.setAdapter(adapter);//4. 添加拖动事件Callback callback = new Callback(adapter);mItemTouchHelper = new ItemTouchHelper(callback);mItemTouchHelper.attachToRecyclerView(recycler_view);}/*** 初始化数据*/private void initData(){names.add("宋江");names.add("卢俊义");names.add("吴用");names.add("公孙胜");names.add("关胜");names.add("林冲");names.add("秦明");names.add("呼延灼");names.add("花荣");names.add("柴进");names.add("李应");names.add("朱仝");names.add("鲁智深");names.add("武松");names.add("董平");names.add("张清");names.add("杨志");names.add("徐宁");names.add("索超");}/*** RecyclerView 适配器*/public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {private RecyclerView mRecyclerView;@Overridepublic void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {super.onAttachedToRecyclerView(recyclerView);this.mRecyclerView = recyclerView;}@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View root_view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_recyclerview, parent, false);return new ViewHolder(root_view);}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {holder.text.setText("" + names.get(position));}@Overridepublic int getItemCount() {return names.size();}public class ViewHolder extends RecyclerView.ViewHolder {TextView text;public ViewHolder(@NonNull View itemView) {super(itemView);text = itemView.findViewById(R.id.text);}}/*** 删除元素调用的方法* @param position*/public void deleteItem(int position) {names.remove(position);notifyItemRemoved(position);}/*** 交换条目元素* @param srcPosition* @param dstPosition*/public void changeItem(int srcPosition, int dstPosition) {// 交换集合中两个元素位置Collections.swap(names, srcPosition, dstPosition);// 刷新界面显示notifyItemMoved(srcPosition, dstPosition);}}}

2、ItemTouchHelper.Callback 回调类

package kim.hsl.recyclerview;import android.util.Log;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;public class Callback extends ItemTouchHelper.Callback {private static final String TAG = "Callback";private MainActivity.Adapter mAdapter;public Callback(MainActivity.Adapter mAdapter) {this.mAdapter = mAdapter;}/*** 设置上下左右动作* 只有在此处打开了指定方向的设置 , 才可以应用具体方向的拖动* @param recyclerView* @param viewHolder* @return*/@Overridepublic int getMovementFlags(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder viewHolder) {// 设置拖动方向, 此处设置上下拖动事件int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;// 设置滑动方向, 此处设置左右侧滑事件int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;// 应用 拖动 和 滑动 设置return makeMovementFlags(dragFlags, swipeFlags);}/*以下是拖动相关方法*//*** 是否启用长按拖动功能* @return*/@Overridepublic boolean isLongPressDragEnabled() {return true;}/*** 拖动幅度设置* 组件在宽度 / 高度 上移动超过该比例 , 就认为拖动触发, 执行拖动相关操作* @param viewHolder* @return*/@Overridepublic float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {// 该案例中, 拖动操作只能上下进行// 拖动超过条目组件高度超过 0.9 倍, 即可触发拖动操作return 0.9f;}/*** 监听滑动事件* 滑动分 水平 / 垂直 两个方向* @param recyclerView* @param viewHolder* @param target* @return*/@Overridepublic boolean onMove(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder viewHolder,@NonNull RecyclerView.ViewHolder target) {// 拖动后交换数据, 该方法中交换 Adapter 中的数据, 并刷新界面Log.i(TAG, "触发拖动交换条目");mAdapter.changeItem(viewHolder.getAdapterPosition(), target.getAdapterPosition());return true;}/*以下是滑动相关方法*//*** 是否启用滑动操作* @return 是否启用 true 启用, false 不启用*/@Overridepublic boolean isItemViewSwipeEnabled() {return true;}/*** 用户滑动距离, 设置的是比例值, 返回值为 0.5 , 就意味着滑动宽度/高度的一半, 才触发侧滑 onSwiped 方法* @param viewHolder* @return*/@Overridepublic float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {return 0.5f;}/*** 滑动判定速度, 每秒移动的像素个数, 达到该速度后, 才可以被判定为滑动* @param defaultValue* @return*/@Overridepublic float getSwipeEscapeVelocity(float defaultValue) {return 5000f;}/*** 手指离开后的动画持续时间* @param recyclerView* @param animationType* @param animateDx* @param animateDy* @return*/@Overridepublic long getAnimationDuration(@NonNull RecyclerView recyclerView,int animationType,float animateDx, float animateDy) {return 200L;}/*** 滑动时的回调操作* @param viewHolder* @param direction*/@Overridepublic void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {Log.i(TAG, "触发侧滑删除条目");// 滑动指定的距离, 达到一定幅度后, 就会触发该方法回调// 这里做的是滑动删除功能, 直接删除滑动项// 该方法中删除指定条目, 并刷新界面mAdapter.deleteItem(viewHolder.getAdapterPosition());}
}

3、执行效果

三、博客资源


博客资源 :

  • GitHub 地址 : https://github.com/han1202012/001_RecyclerView

【Android 事件分发】ItemTouchHelper 实现拖动排序相关推荐

  1. 【Android 事件分发】ItemTouchHelper 简介 ( 拖动/滑动事件 | ItemTouchHelper.Callback 回调 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  2. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  3. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  4. 【Android 事件分发】ItemTouchHelper 事件分发源码分析 ( 绑定 RecyclerView )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  5. 【Android 事件分发】ItemTouchHelper 实现侧滑删除

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  6. 【Android 事件分发】MotionEvent.ACTION_DOWN 按下事件分发流程( Activity | ViewGroup | View )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  7. 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 七 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  8. 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 六 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  9. 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

最新文章

  1. Scrum中文网-是否需要在Sprint计划会上分完所有任务?
  2. MySQL Date,DateTime和Timestamp类型
  3. 2021年4月27日 华为Cloud AI 通用软件开发实习面试(一面)
  4. 多台服务器搭建Spark集群
  5. visio任意区域填充斜线阴影_DX12渲染管线(6) - 级联阴影与距离场阴影
  6. 事业单位职称工资计算机,终于!事业单位绩效工资、职称变了!关系上千万人收入!...
  7. Linux0.11内核剖析--内核体系结构
  8. lib 和 dll 的区别、生成以及使用详解
  9. C# 对垒 VB.NET C#不行了?
  10. kuberneters dashboard认证及分级授权
  11. textarea的不可拉伸和不可编辑
  12. c语言依次调用字符串中的元素,C语言经典题目(某校复试真题)
  13. 自制VBS自动刷屏器,再也不怕刷屏刷不过别人了
  14. 微信公众号 关注推送消息报错 45047
  15. VS使用教程(使用visual studio编写C语言程序),编写c的入门教程
  16. 无法安装打印机,打印处理器不存在
  17. 打开office word 2003 时出现了“出现问题需要关闭,是否发送错误报告”
  18. 支付宝 实现 移动网页支付、PC网页支付、混合APP支付(支持微信支付)
  19. 有效发布促成高效软文营销 | 媒介启航
  20. Android之九宫格解锁的实现

热门文章

  1. JspServlet之Cookie
  2. 5.1 指针与地址 (C)
  3. 2018-12-10
  4. mysql 自定义提示符
  5. std::shuffle-c++
  6. HttpUrlConnection get和post简单实现(疑惑解决)
  7. Android 布局中 如何使控件居中
  8. 将近一半的用户希望能够在两秒内或者更短的时间内打开网站
  9. office 2007全屏快捷键|设置
  10. ImportError: Failed to import pydot. You must install pydot and graphviz for `pydotprint` to work.