【Android 事件分发】ItemTouchHelper 实现拖动排序
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 方法 ;
上面案例中設置的拖動幅度是 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 实现拖动排序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 事件分发】ItemTo
- 下一篇: 【Android 事件分发】ItemTo