您的位置:首页 > 其它

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

2016-08-18 21:51 549 查看
ItemTouchHelper是v7包中的用于为RecyclerView中Item操作提供帮助的工具类。

[java]
view plain
copy

/**

* This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

* <p>

* XXXXXXXXXXXXXXXXXXXXXXXXXXXXX

*/

public class ItemTouchHelper extends RecyclerView.ItemDecoration

implements RecyclerView.OnChildAttachStateChangeListener {

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

[java]
view plain
copy

/**

* This class is the contract between ItemTouchHelper and your application. It lets you control

* which touch behaviors are enabled per each ViewHolder and also receive callbacks when user

* performs these actions.

<span style="white-space:pre"> </span>XXXXXXXX

*/

@SuppressWarnings("UnusedParameters")

public abstract static class Callback {

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

[java]
view plain
copy

/**

* Should return a composite flag which defines the enabled move directions in each state

* (idle, swiping, dragging).

* <p>

* Instead of composing this flag manually, you can use {@link #makeMovementFlags(int,

* int)}

* or {@link #makeFlag(int, int)}.

* <p>

* This flag is composed of 3 sets of 8 bits, where first 8 bits are for IDLE state, next

* 8 bits are for SWIPE state and third 8 bits are for DRAG state.

* Each 8 bit sections can be constructed by simply OR'ing direction flags defined in

* {@link ItemTouchHelper}.

* <p>

* For example, if you want it to allow swiping LEFT and RIGHT but only allow starting to

* swipe by swiping RIGHT, you can return:

* <pre>

* makeFlag(ACTION_STATE_IDLE, RIGHT) | makeFlag(ACTION_STATE_SWIPE, LEFT | RIGHT);

* </pre>

* This means, allow right movement while IDLE and allow right and left movement while

* swiping.

*

* @param recyclerView The RecyclerView to which ItemTouchHelper is attached.

* @param viewHolder The ViewHolder for which the movement information is necessary.

* @return flags specifying which movements are allowed on this ViewHolder.

* @see #makeMovementFlags(int, int)

* @see #makeFlag(int, int)

*/

public abstract int getMovementFlags(RecyclerView recyclerView,

ViewHolder viewHolder);

[java]
view plain
copy

/**

* Called when ItemTouchHelper wants to move the dragged item from its old position to

* the new position.

* <p>

* If this method returns true, ItemTouchHelper assumes {@code viewHolder} has been moved

* to the adapter position of {@code target} ViewHolder

* ({@link ViewHolder#getAdapterPosition()

* ViewHolder#getAdapterPosition()}).

* <p>

* If you don't support drag & drop, this method will never be called.

*

* @param recyclerView The RecyclerView to which ItemTouchHelper is attached to.

* @param viewHolder The ViewHolder which is being dragged by the user.

* @param target The ViewHolder over which the currently active item is being

* dragged.

* @return True if the {@code viewHolder} has been moved to the adapter position of

* {@code target}.

* @see #onMoved(RecyclerView, ViewHolder, int, ViewHolder, int, int, int)

*/

public abstract boolean onMove(RecyclerView recyclerView,

ViewHolder viewHolder, ViewHolder target);

/**

* Called when a ViewHolder is swiped by the user.

* <p>

* If you are returning relative directions ({@link #START} , {@link #END}) from the

* {@link #getMovementFlags(RecyclerView, ViewHolder)} method, this method

* will also use relative directions. Otherwise, it will use absolute directions.

* <p>

* If you don't support swiping, this method will never be called.

* <p>

* ItemTouchHelper will keep a reference to the View until it is detached from

* RecyclerView.

* As soon as it is detached, ItemTouchHelper will call

* {@link #clearView(RecyclerView, ViewHolder)}.

*

* @param viewHolder The ViewHolder which has been swiped by the user.

* @param direction The direction to which the ViewHolder is swiped. It is one of

* {@link #UP}, {@link #DOWN},

* {@link #LEFT} or {@link #RIGHT}. If your

* {@link #getMovementFlags(RecyclerView, ViewHolder)}

* method

* returned relative flags instead of {@link #LEFT} / {@link #RIGHT};

* `direction` will be relative as well. ({@link #START} or {@link

* #END}).

*/

public abstract void onSwiped(ViewHolder viewHolder, int direction);

[java]
view plain
copy

<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

[java]
view plain
copy

<strong><onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target):</strong>在拖拽Item的时候调用该方法,第一个ViewHolder代表正在拖拽的Item,第二个ViewHolder代表目标Item

[java]
view plain
copy

[java]
view plain
copy

</pre><pre name="code" class="java"><strong>onSwiped(ViewHolder viewHolder, int direction):</strong>在滑动Item的时候调用该方法,第二个参数代表拖拽方向的相对位置。

[java]
view plain
copy

[java]
view plain
copy

</pre><pre name="code" class="java">实际运用中还有几个方法需要重写:

[java]
view plain
copy

[java]
view plain
copy

</pre><pre name="code" class="java"><strong>isLongPressDragEnabled():</strong>返回true代表支持当长按的时候开始拖拽操作

[java]
view plain
copy

[java]
view plain
copy

</pre><pre name="code" class="java"><strong>isItemViewSwipeEnabled():</strong>返回true代表支持ItemView的左右滑动

[java]
view plain
copy

[java]
view plain
copy

</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

[java]
view plain
copy

</pre><pre name="code" class="java"><strong>onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) :</strong>在Item选中状态该表的时候会调用该方法,可以重写改方法,当选中时,写一些动画逻辑。

[java]
view plain
copy

</pre><pre name="code" class="java"><strong>clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) : </strong>当用户的操作和动画已经结束的时候调用该方法,可以重写该方法,恢复Item的初始状态

[java]
view plain
copy

说了这么多,不如用代码来解释。

[java]
view plain
copy

[java]
view plain
copy

<span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="java"><pre name="code" class="java">

import android.graphics.Canvas;

import android.support.v7.widget.RecyclerView;

import android.support.v7.widget.helper.ItemTouchHelper;

import android.util.Log;

/**

* Created by haggling on 2015/8/6.

*/

public class MyTouchHelperCallback extends ItemTouchHelper.Callback {

public static final float ALPHA_FULL = 1.0f;

private final ItemTouchHelperAdapter adapter;

public MyTouchHelperCallback(ItemTouchHelperAdapter adapter) {

this.adapter = adapter;

}

/**

* 支持长按开始拖拽

* @return

*/

@Override

public boolean isLongPressDragEnabled() {

return true;

}

/**

* 支持左右滑动

* @return

*/

@Override

public boolean isItemViewSwipeEnabled() {

return true;

}

@Override

public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

//滑动的时候支持的方向

int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;

//拖拽的时候支持的方向

int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;

//必须调用该方法告诉ItemTouchHelper支持的flags

return makeMovementFlags(dragFlags, swipeFlags);

}

/**

* Item移动的时候调用该方法

* @param recyclerView

* @param viewHolder

* @param target

* @return

*/

@Override

public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

if(viewHolder.getItemViewType() != target.getItemViewType()) {

return false;

}

adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());

return true;

}

/**

* Item滑动的时候调用该方法

* @param viewHolder

* @param direction

*/

@Override

public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {

adapter.onItemDismiss(viewHolder.getAdapterPosition());

}

@Override

public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {

if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {

//左右滑动时改变Item的透明度

final float alpha = ALPHA_FULL - Math.abs(dX) / (float)viewHolder.itemView.getWidth();

viewHolder.itemView.setAlpha(alpha);

viewHolder.itemView.setTranslationX(dX);

} else {

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

}

}

@Override

public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {

if(actionState != ItemTouchHelper.ACTION_STATE_IDLE) {

Log.d("ACTION_STATE_IDLE", "ACTION_STATE_IDLE");

if(viewHolder instanceof ItemTouchHelperViewHolder) {

Log.d("instanceof", "instanceof");

ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;

itemViewHolder.onItemSelected();

}

}

super.onSelectedChanged(viewHolder, actionState);

}

@Override

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

super.clearView(recyclerView, viewHolder);

Log.d("clearView", "clearView");

viewHolder.itemView.setAlpha(ALPHA_FULL);

if(viewHolder instanceof ItemTouchHelperViewHolder) {

ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;

itemViewHolder.onItemClear();

}

}

}

[java]
view plain
copy

<strong>其中有三个接口</strong>

[java]
view plain
copy

<span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="java">

public interface ItemTouchHelperAdapter {

boolean onItemMove(int fromPosition, int toPosition);

void onItemDismiss(int position);

}

[java]
view plain
copy

public interface ItemTouchHelperViewHolder {

void onItemSelected();

void onItemClear();

}

[java]
view plain
copy

/**

* Created by haoqinling on 2015/8/6.

*/

import android.support.v7.widget.RecyclerView;

public interface OnStartDragListener {

void onStartDrag(RecyclerView.ViewHolder viewHolder);

}

RecyclerView的Adapter

[java]
view plain
copy

package com.cecgt.haoqinling.myapplication.helper;

import android.animation.AnimatorSet;

import android.animation.ObjectAnimator;

import android.content.Context;

import android.graphics.Color;

import android.support.v4.view.MotionEventCompat;

import android.support.v7.widget.RecyclerView;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.DecelerateInterpolator;

import android.widget.ImageView;

import android.widget.TextView;

import com.cecgt.haoqinling.myapplication.R;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Collections;

import java.util.List;

/**

* Created by haoqinling on 2015/7/8.

*/

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ItemViewHolder> implements ItemTouchHelperAdapter{

private final List<String> mItems = new ArrayList<>();

private final OnStartDragListener mDragStartListener;

public RecyclerViewAdapter(Context context, OnStartDragListener dragStartListener) {

mDragStartListener = dragStartListener;

mItems.addAll(Arrays.asList(context.getResources().getStringArray(R.array.dummy_items)));

}

@Override

public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main, parent, false);

ItemViewHolder itemViewHolder = new ItemViewHolder(view);

return itemViewHolder;

}

@Override

public void onBindViewHolder(final ItemViewHolder holder, int position) {

holder.textView.setText(mItems.get(position));

//当点击Item上面的图标的时候开始拖拽

holder.imageView.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {

mDragStartListener.onStartDrag(holder);

}

return false;

}

});

}

@Override

public int getItemCount() {

return mItems.size();

}

@Override

public boolean onItemMove(int fromPosition, int toPosition) {

Collections.swap(mItems, fromPosition, toPosition);

notifyItemMoved(fromPosition, toPosition);

return true;

}

@Override

public void onItemDismiss(int position) {

mItems.remove(position);

notifyItemRemoved(position);

}

public static class ItemViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder {

private final TextView textView;

private final ImageView imageView;

AnimatorSet upSet, downSet;

//private View itemView;

public ItemViewHolder(View itemView) {

super(itemView);

// this.itemView = itemView;

textView = (TextView) itemView.findViewById(R.id.text);

imageView = (ImageView) itemView.findViewById(R.id.handle);

//创建动画

ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(itemView, "scaleX", 0.95f);

ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(itemView, "scaleY", 0.95f);

ObjectAnimator upAnim = ObjectAnimator.ofFloat(itemView, "translationZ", 10);

ObjectAnimator upColor = ObjectAnimator.ofArgb(itemView, "backgroundColor", Color.LTGRAY);

upSet = new AnimatorSet();

upSet.playSequentially(scaleXAnim, scaleYAnim, upAnim, upColor);

upSet.setDuration(100);

upSet.setInterpolator(new DecelerateInterpolator());

ObjectAnimator downAnim = ObjectAnimator.ofFloat(itemView, "translationZ", 0);

ObjectAnimator scaleXDownAnim = ObjectAnimator.ofFloat(itemView, "scaleX", 1.0f);

ObjectAnimator scaleYDownAnim = ObjectAnimator.ofFloat(itemView, "scaleY", 1.0f);

ObjectAnimator downColor = ObjectAnimator.ofArgb(itemView, "backgroundColor", 0);

downSet = new AnimatorSet();

downSet.playSequentially(scaleXDownAnim, scaleYDownAnim, downAnim, downColor);

downSet.setDuration(100);

downSet.setInterpolator(new DecelerateInterpolator());

}

@Override

public void onItemSelected() {

itemView.clearAnimation();

upSet.start();

}

@Override

public void onItemClear() {

itemView.clearAnimation();

downSet.start();

}

}

}

在绑定adapter后需要把ItemTouchHelper关联到RecyclerView上面去 :mItemTouchHelper.attachToRecyclerView(recyclerView);

[java]
view plain
copy

recyclerView.setHasFixedSize(true);

recyclerView.setAdapter(adapter);

recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);

mItemTouchHelper = new ItemTouchHelper(callback);

mItemTouchHelper.attachToRecyclerView(recyclerView);

来看下效果:



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

原作者源码地址:https://github.com/iPaulPro/Android-ItemTouchHelper-Demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: