ItemTouchHelper,让你轻松打造RecyclerView中Item的滑动删除,拖拽交换

来源:互联网 发布:北京seo排名优化公司 编辑:程序博客网 时间:2024/05/29 11:57

ItemTouchHelper是v7包中的用于为RecyclerView中Item操作提供帮助的工具类。


[java]  view plain copy
  1. /** 
  2.  * This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView. 
  3.  * <p> 
  4.  * XXXXXXXXXXXXXXXXXXXXXXXXXXXXX 
  5.  */  
  6. public class ItemTouchHelper extends RecyclerView.ItemDecoration  
  7.         implements RecyclerView.OnChildAttachStateChangeListener {  


它内部封装了 Item的左右滑动,上下平移的操作,并向外提供了一个Callback抽象类让我们使用



[java]  view plain copy
  1. /** 
  2.     * This class is the contract between ItemTouchHelper and your application. It lets you control 
  3.     * which touch behaviors are enabled per each ViewHolder and also receive callbacks when user 
  4.     * performs these actions. 
  5.    <span style="white-space:pre">     </span>XXXXXXXX 
  6.     */  
  7.    @SuppressWarnings("UnusedParameters")  
  8.    public abstract static class Callback {  

我们使用的 时候只需继承该类并实现其中的几个抽象方法就可以轻松实现诸如Item的滑动删除,拖拽交换。不用我们再自己去实现复杂的交互逻辑。默认一共有三个抽象方法需要实现

[java]  view plain copy
  1. /** 
  2.         * Should return a composite flag which defines the enabled move directions in each state 
  3.         * (idle, swiping, dragging). 
  4.         * <p> 
  5.         * Instead of composing this flag manually, you can use {@link #makeMovementFlags(int, 
  6.         * int)} 
  7.         * or {@link #makeFlag(int, int)}. 
  8.         * <p> 
  9.         * This flag is composed of 3 sets of 8 bits, where first 8 bits are for IDLE state, next 
  10.         * 8 bits are for SWIPE state and third 8 bits are for DRAG state. 
  11.         * Each 8 bit sections can be constructed by simply OR'ing direction flags defined in 
  12.         * {@link ItemTouchHelper}. 
  13.         * <p> 
  14.         * For example, if you want it to allow swiping LEFT and RIGHT but only allow starting to 
  15.         * swipe by swiping RIGHT, you can return: 
  16.         * <pre> 
  17.         *      makeFlag(ACTION_STATE_IDLE, RIGHT) | makeFlag(ACTION_STATE_SWIPE, LEFT | RIGHT); 
  18.         * </pre> 
  19.         * This means, allow right movement while IDLE and allow right and left movement while 
  20.         * swiping. 
  21.         * 
  22.         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached. 
  23.         * @param viewHolder   The ViewHolder for which the movement information is necessary. 
  24.         * @return flags specifying which movements are allowed on this ViewHolder. 
  25.         * @see #makeMovementFlags(int, int) 
  26.         * @see #makeFlag(int, int) 
  27.         */  
  28.        public abstract int getMovementFlags(RecyclerView recyclerView,  
  29.                ViewHolder viewHolder);  
[java]  view plain copy
  1. /** 
  2.         * Called when ItemTouchHelper wants to move the dragged item from its old position to 
  3.         * the new position. 
  4.         * <p> 
  5.         * If this method returns true, ItemTouchHelper assumes {@code viewHolder} has been moved 
  6.         * to the adapter position of {@code target} ViewHolder 
  7.         * ({@link ViewHolder#getAdapterPosition() 
  8.         * ViewHolder#getAdapterPosition()}). 
  9.         * <p> 
  10.         * If you don't support drag & drop, this method will never be called. 
  11.         * 
  12.         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to. 
  13.         * @param viewHolder   The ViewHolder which is being dragged by the user. 
  14.         * @param target       The ViewHolder over which the currently active item is being 
  15.         *                     dragged. 
  16.         * @return True if the {@code viewHolder} has been moved to the adapter position of 
  17.         * {@code target}. 
  18.         * @see #onMoved(RecyclerView, ViewHolder, int, ViewHolder, int, int, int) 
  19.         */  
  20.        public abstract boolean onMove(RecyclerView recyclerView,  
  21.                ViewHolder viewHolder, ViewHolder target);  
  22.   
  23.   
  24.  /** 
  25.         * Called when a ViewHolder is swiped by the user. 
  26.         * <p> 
  27.         * If you are returning relative directions ({@link #START} , {@link #END}) from the 
  28.         * {@link #getMovementFlags(RecyclerView, ViewHolder)} method, this method 
  29.         * will also use relative directions. Otherwise, it will use absolute directions. 
  30.         * <p> 
  31.         * If you don't support swiping, this method will never be called. 
  32.         * <p> 
  33.         * ItemTouchHelper will keep a reference to the View until it is detached from 
  34.         * RecyclerView. 
  35.         * As soon as it is detached, ItemTouchHelper will call 
  36.         * {@link #clearView(RecyclerView, ViewHolder)}. 
  37.         * 
  38.         * @param viewHolder The ViewHolder which has been swiped by the user. 
  39.         * @param direction  The direction to which the ViewHolder is swiped. It is one of 
  40.         *                   {@link #UP}, {@link #DOWN}, 
  41.         *                   {@link #LEFT} or {@link #RIGHT}. If your 
  42.         *                   {@link #getMovementFlags(RecyclerView, ViewHolder)} 
  43.         *                   method 
  44.         *                   returned relative flags instead of {@link #LEFT} / {@link #RIGHT}; 
  45.         *                   `direction` will be relative as well. ({@link #START} or {@link 
  46.         *                   #END}). 
  47.         */  
  48.        public abstract void onSwiped(ViewHolder viewHolder, int direction);  


[java]  view plain copy
  1. <strong>getMovementFlags(RecyclerView recyclerView,ViewHolder viewHolder):</strong>该方法的返回值决定的所支持的滑动,拖拽的方向,有ItemTouchHelper.UP, ItemTouchHelper.DOWN ,ItemTouchHelper.LEFT,ItemTouchHelper.RIGHT,ItemTouchHelper.START, ItemTouchHelper.END等几种,比如划动删除的时候,只需要返ItemTouchHelper.LEFT,ItemTouchHelper.RIGHT,即可以支持左右的滑动删除。  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. <strong><onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target):</strong>在拖拽Item的时候调用该方法,第一个ViewHolder代表正在拖拽的Item,第二个ViewHolder代表目标Item  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. </pre><pre name="code" class="java"><strong>onSwiped(ViewHolder viewHolder, int direction):</strong>在滑动Item的时候调用该方法,第二个参数代表拖拽方向的相对位置。  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. </pre><pre name="code" class="java">实际运用中还有几个方法需要重写:  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. </pre><pre name="code" class="java"><strong>isLongPressDragEnabled():</strong>返回true代表支持当长按的时候开始拖拽操作  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. </pre><pre name="code" class="java"><strong>isItemViewSwipeEnabled():</strong>返回true代表支持ItemView的左右滑动  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. </pre><pre name="code" class="java"><strong>onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) :</strong>当系统绘制RecyclerView的时候会调用该方法,你可以重写改方法在里面写动画逻辑。其中cationState一共有三种,IDLE, SWIPE, DRAG分别代表了 静止,滑动,拖拽三种状态,  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. </pre><pre name="code" class="java"><strong>onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) :</strong>在Item选中状态该表的时候会调用该方法,可以重写改方法,当选中时,写一些动画逻辑。  
[java]  view plain copy
  1. </pre><pre name="code" class="java"><strong>clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) : </strong>当用户的操作和动画已经结束的时候调用该方法,可以重写该方法,恢复Item的初始状态  

[java]  view plain copy
  1. 说了这么多,不如用代码来解释。  
[java]  view plain copy
  1.   
[java]  view plain copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="java"><pre name="code" class="java">  
  2. import android.graphics.Canvas;  
  3. import android.support.v7.widget.RecyclerView;  
  4. import android.support.v7.widget.helper.ItemTouchHelper;  
  5. import android.util.Log;  
  6.   
  7. /** 
  8.  * Created by haggling on 2015/8/6. 
  9.  */  
  10. public class MyTouchHelperCallback extends ItemTouchHelper.Callback {  
  11.   
  12.     public static final float ALPHA_FULL = 1.0f;  
  13.   
  14.     private final ItemTouchHelperAdapter adapter;  
  15.   
  16.     public MyTouchHelperCallback(ItemTouchHelperAdapter adapter) {  
  17.         this.adapter = adapter;  
  18.     }  
  19.   
  20.     /** 
  21.      * 支持长按开始拖拽 
  22.      * @return 
  23.      */  
  24.     @Override  
  25.     public boolean isLongPressDragEnabled() {  
  26.         return true;  
  27.     }  
  28.   
  29.     /** 
  30.      * 支持左右滑动 
  31.      * @return 
  32.      */  
  33.     @Override  
  34.     public boolean isItemViewSwipeEnabled() {  
  35.         return true;  
  36.     }  
  37.   
  38.     @Override  
  39.     public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {  
  40.         //滑动的时候支持的方向  
  41.         int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;  
  42.         //拖拽的时候支持的方向  
  43.         int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;  
  44.   
  45.         //必须调用该方法告诉ItemTouchHelper支持的flags  
  46.         return makeMovementFlags(dragFlags, swipeFlags);  
  47.     }  
  48.   
  49.     /** 
  50.      * Item移动的时候调用该方法 
  51.      * @param recyclerView 
  52.      * @param viewHolder 
  53.      * @param target 
  54.      * @return 
  55.      */  
  56.     @Override  
  57.     public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {  
  58.         if(viewHolder.getItemViewType() != target.getItemViewType()) {  
  59.             return false;  
  60.         }  
  61.         adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());  
  62.         return true;  
  63.     }  
  64.   
  65.     /** 
  66.      * Item滑动的时候调用该方法 
  67.      * @param viewHolder 
  68.      * @param direction 
  69.      */  
  70.     @Override  
  71.     public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {  
  72.         adapter.onItemDismiss(viewHolder.getAdapterPosition());  
  73.     }  
  74.   
  75.     @Override  
  76.     public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {  
  77.         if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {  
  78.             //左右滑动时改变Item的透明度  
  79.             final float alpha = ALPHA_FULL - Math.abs(dX) / (float)viewHolder.itemView.getWidth();  
  80.             viewHolder.itemView.setAlpha(alpha);  
  81.             viewHolder.itemView.setTranslationX(dX);  
  82.         } else {  
  83.             super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);  
  84.         }  
  85.   
  86.     }  
  87.   
  88.     @Override  
  89.     public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {  
  90.         if(actionState != ItemTouchHelper.ACTION_STATE_IDLE) {  
  91.             Log.d("ACTION_STATE_IDLE""ACTION_STATE_IDLE");  
  92.             if(viewHolder instanceof ItemTouchHelperViewHolder) {  
  93.                 Log.d("instanceof""instanceof");  
  94.                 ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;  
  95.                 itemViewHolder.onItemSelected();  
  96.             }  
  97.         }  
  98.         super.onSelectedChanged(viewHolder, actionState);  
  99.     }  
  100.   
  101.     @Override  
  102.     public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {  
  103.         super.clearView(recyclerView, viewHolder);  
  104.   
  105.         Log.d("clearView""clearView");  
  106.         viewHolder.itemView.setAlpha(ALPHA_FULL);  
  107.   
  108.         if(viewHolder instanceof ItemTouchHelperViewHolder) {  
  109.             ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;  
  110.             itemViewHolder.onItemClear();  
  111.         }  
  112.     }  
  113. }  


[java]  view plain copy
  1. <strong>其中有三个接口</strong>  

[java]  view plain copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="java">  
  2.   
  3. public interface ItemTouchHelperAdapter {  
  4.   
  5.     
  6.     boolean onItemMove(int fromPosition, int toPosition);  
  7.   
  8.   
  9.     
  10.     void onItemDismiss(int position);  
  11. }  


[java]  view plain copy
  1. public interface ItemTouchHelperViewHolder {  
  2.   
  3.      
  4.     void onItemSelected();  
  5.   
  6.   
  7.      
  8.     void onItemClear();  
  9. }  

[java]  view plain copy
  1. /** 
  2.  * Created by haoqinling on 2015/8/6. 
  3.  */  
  4.   
  5. import android.support.v7.widget.RecyclerView;  
  6.   
  7.   
  8. public interface OnStartDragListener {  
  9.   
  10.   
  11.     void onStartDrag(RecyclerView.ViewHolder viewHolder);  
  12.   
  13. }  


RecyclerView的Adapter


[java]  view plain copy
  1. package com.cecgt.haoqinling.myapplication.helper;  
  2.   
  3. import android.animation.AnimatorSet;  
  4. import android.animation.ObjectAnimator;  
  5. import android.content.Context;  
  6. import android.graphics.Color;  
  7. import android.support.v4.view.MotionEventCompat;  
  8. import android.support.v7.widget.RecyclerView;  
  9. import android.view.LayoutInflater;  
  10. import android.view.MotionEvent;  
  11. import android.view.View;  
  12. import android.view.ViewGroup;  
  13. import android.view.animation.DecelerateInterpolator;  
  14. import android.widget.ImageView;  
  15. import android.widget.TextView;  
  16.   
  17. import com.cecgt.haoqinling.myapplication.R;  
  18.   
  19. import java.util.ArrayList;  
  20. import java.util.Arrays;  
  21. import java.util.Collections;  
  22. import java.util.List;  
  23.   
  24. /** 
  25.  * Created by haoqinling on 2015/7/8. 
  26.  */  
  27. public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ItemViewHolder> implements ItemTouchHelperAdapter{  
  28.   
  29.     private final List<String> mItems = new ArrayList<>();  
  30.   
  31.     private final OnStartDragListener mDragStartListener;  
  32.   
  33.     public RecyclerViewAdapter(Context context, OnStartDragListener dragStartListener) {  
  34.         mDragStartListener = dragStartListener;  
  35.         mItems.addAll(Arrays.asList(context.getResources().getStringArray(R.array.dummy_items)));  
  36.     }  
  37.   
  38.     @Override  
  39.     public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  40.         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main, parent, false);  
  41.         ItemViewHolder itemViewHolder = new ItemViewHolder(view);  
  42.         return itemViewHolder;  
  43.     }  
  44.   
  45.     @Override  
  46.     public void onBindViewHolder(final ItemViewHolder holder, int position) {  
  47.         holder.textView.setText(mItems.get(position));  
  48.   
  49.         //当点击Item上面的图标的时候开始拖拽  
  50.         holder.imageView.setOnTouchListener(new View.OnTouchListener() {  
  51.             @Override  
  52.             public boolean onTouch(View v, MotionEvent event) {  
  53.                 if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {  
  54.                     mDragStartListener.onStartDrag(holder);  
  55.                 }  
  56.                 return false;  
  57.             }  
  58.         });  
  59.     }  
  60.   
  61.     @Override  
  62.     public int getItemCount() {  
  63.         return mItems.size();  
  64.     }  
  65.   
  66.     @Override  
  67.     public boolean onItemMove(int fromPosition, int toPosition) {  
  68.         Collections.swap(mItems, fromPosition, toPosition);  
  69.         notifyItemMoved(fromPosition, toPosition);  
  70.         return true;  
  71.     }  
  72.   
  73.     @Override  
  74.     public void onItemDismiss(int position) {  
  75.         mItems.remove(position);  
  76.         notifyItemRemoved(position);  
  77.     }  
  78.   
  79.     public static class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {  
  80.   
  81.         private final TextView textView;  
  82.         private final ImageView imageView;  
  83.         AnimatorSet upSet, downSet;  
  84.         //private View itemView;  
  85.   
  86.         public ItemViewHolder(View itemView) {  
  87.             super(itemView);  
  88.            // this.itemView = itemView;  
  89.             textView = (TextView) itemView.findViewById(R.id.text);  
  90.             imageView = (ImageView) itemView.findViewById(R.id.handle);  
  91.   
  92.             //创建动画  
  93.             ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(itemView, "scaleX"0.95f);  
  94.             ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(itemView, "scaleY"0.95f);  
  95.             ObjectAnimator upAnim = ObjectAnimator.ofFloat(itemView, "translationZ"10);  
  96.             ObjectAnimator upColor = ObjectAnimator.ofArgb(itemView, "backgroundColor", Color.LTGRAY);  
  97.             upSet = new AnimatorSet();  
  98.             upSet.playSequentially(scaleXAnim, scaleYAnim, upAnim, upColor);  
  99.             upSet.setDuration(100);  
  100.             upSet.setInterpolator(new DecelerateInterpolator());  
  101.   
  102.             ObjectAnimator downAnim = ObjectAnimator.ofFloat(itemView, "translationZ"0);  
  103.             ObjectAnimator scaleXDownAnim = ObjectAnimator.ofFloat(itemView, "scaleX"1.0f);  
  104.             ObjectAnimator scaleYDownAnim = ObjectAnimator.ofFloat(itemView, "scaleY"1.0f);  
  105.             ObjectAnimator downColor = ObjectAnimator.ofArgb(itemView, "backgroundColor"0);  
  106.             downSet = new AnimatorSet();  
  107.             downSet.playSequentially(scaleXDownAnim, scaleYDownAnim, downAnim, downColor);  
  108.             downSet.setDuration(100);  
  109.             downSet.setInterpolator(new DecelerateInterpolator());  
  110.         }  
  111.   
  112.         @Override  
  113.         public void onItemSelected() {  
  114.             itemView.clearAnimation();  
  115.   
  116.             upSet.start();  
  117.         }  
  118.   
  119.         @Override  
  120.         public void onItemClear() {  
  121.             itemView.clearAnimation();  
  122.   
  123.             downSet.start();  
  124.         }  
  125.     }  
  126. }  
在绑定adapter后需要把ItemTouchHelper关联到RecyclerView上面去 :mItemTouchHelper.attachToRecyclerView(recyclerView);

[java]  view plain copy
  1. recyclerView.setHasFixedSize(true);  
  2.        recyclerView.setAdapter(adapter);  
  3.        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));  
  4.   
  5.        ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);  
  6.        mItemTouchHelper = new ItemTouchHelper(callback);  
  7.        mItemTouchHelper.attachToRecyclerView(recyclerView);  

来看下效果:


参考链接:https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-b9456d2b1aaf

原作者源码地址:https://github.com/iPaulPro/Android-ItemTouchHelper-Demo

0 0
原创粉丝点击