赞
踩
RecyclerView除了有强大的列表功能外,自身还带有Item拖拽和滑动功能,对于有这方面需求的开发来讲,可以节省不少时间。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_drag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView android:layout_width="66dp" android:layout_height="66dp" app:cardBackgroundColor="#1dd9c4" app:cardCornerRadius="12dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textColor="@color/white" android:textSize="36sp" android:textStyle="bold" /> </androidx.cardview.widget.CardView>
public class DragAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List data = new ArrayList(); private Context context; public DragAdapter(Context context) { this.context = context; initData(); } /** * 添加数据 */ private void initData() { data.clear(); for (int i = 1; i < 10; i++) { data.add(i); } } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View inflate = LayoutInflater.from(context).inflate(R.layout.item_drag, null); return new CardViewHold(inflate); } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { CardViewHold viewHold = (CardViewHold) holder; viewHold.tvContent.setText("" + data.get(position)); } @Override public int getItemCount() { return data.size(); } class CardViewHold extends RecyclerView.ViewHolder { TextView tvContent; public CardViewHold(@NonNull View itemView) { super(itemView); tvContent = itemView.findViewById(R.id.tv_content); } } }
// 表格布局,3列
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
recyclerView.setLayoutManager(gridLayoutManager);
DragAdapter dragAdapter = new DragAdapter(this);
recyclerView.setAdapter(dragAdapter);
设置为3x3的表格布局。
public interface ItemDragTouchHelper { /** * 交换 * * @param source * @param target */ void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target); /** * 选中 * * @param source */ void onItemSelect(RecyclerView.ViewHolder source); /** * 状态清除 * * @param source */ void onItemClear(RecyclerView.ViewHolder source); }
定义三种事件,Item交换,Item被选中,Item选中状态清除。若是有其他需求,可以自行添加,比如删除,左右滑动等。
public class ItemDragTouchHelperCallback extends ItemTouchHelper.Callback { private ItemDragTouchHelper helper; public ItemDragTouchHelperCallback(ItemDragTouchHelper helper) { this.helper = helper; } @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 viewHolder, @NonNull RecyclerView.ViewHolder target) { helper.onItemMove(viewHolder, target); return true; } @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { } /** * @return */ @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return false; } @Override public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); if (!recyclerView.isComputingLayout()) { helper.onItemClear(viewHolder); } } @Override public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) { super.onSelectedChanged(viewHolder, actionState); if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { helper.onItemSelect(viewHolder); } } }
通过继承ItemTouchHelper.Callback可以实现具体的拖拽功能回调。这里设置的是可以在四个方向进行长按拖拽,但不可滑动。
/** * 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(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder);
同时取这几个值就可以实现多个方向的拖拽,若是对方向有要求可以根据需要单独设置。
/** * Convenience method to create movement flags. * <p> * For instance, if you want to let your items be drag & dropped vertically and swiped * left to be dismissed, you can call this method with: * <code>makeMovementFlags(UP | DOWN, LEFT);</code> * * @param dragFlags The directions in which the item can be dragged. * @param swipeFlags The directions in which the item can be swiped. * @return Returns an integer composed of the given drag and swipe flags. */ public static int makeMovementFlags(int dragFlags, int swipeFlags) { return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags) | makeFlag(ACTION_STATE_SWIPE, swipeFlags) | makeFlag(ACTION_STATE_DRAG, dragFlags); }
/** * 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#getAbsoluteAdapterPosition() * ViewHolder#getAdapterPositionInRecyclerView()}). * <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(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder, @NonNull ViewHolder target);
当返回true时,进行拖拽从一个位置到另一个位置会调用该方法,具体变换逻辑用户自行处理。
/** * 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(@NonNull ViewHolder viewHolder, int direction);
若是没有滑动功能就不做处理。
返回true可长按拖动,即本文指的拖拽功能。
返回false即Item不可滑动。
/** * Called by the ItemTouchHelper when the user interaction with an element is over and it * also completed its animation. * <p> * This is a good place to clear all changes on the View that was done in * {@link #onSelectedChanged(RecyclerView.ViewHolder, int)}, * {@link #onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int, * boolean)} or * {@link #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, boolean)}. * * @param recyclerView The RecyclerView which is controlled by the ItemTouchHelper. * @param viewHolder The View that was interacted by the user. */ public void clearView(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) { ItemTouchUIUtilImpl.INSTANCE.clearView(viewHolder.itemView); }
交互完成后调用该方法,此时可以做相关处理,关闭动画,开启其他动画,恢复正常状态等,但需要等RecycleView计算布局完成后再。
/** * Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed. * <p/> * If you override this method, you should call super. * * @param viewHolder The new ViewHolder that is being swiped or dragged. Might be null if * it is cleared. * @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE}, * {@link ItemTouchHelper#ACTION_STATE_SWIPE} or * {@link ItemTouchHelper#ACTION_STATE_DRAG}. * @see #clearView(RecyclerView, RecyclerView.ViewHolder) */ public void onSelectedChanged(@Nullable ViewHolder viewHolder, int actionState) { if (viewHolder != null) { ItemTouchUIUtilImpl.INSTANCE.onSelected(viewHolder.itemView); } }
Item被选中后调用该方法,作用和clearView(RecyclerView, RecyclerView.ViewHolder)差不多。
需要重写的方法还有一些,可根据具体需求选择性重写。
public class DragAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements ItemDragTouchHelper { ... @Override public void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { int fromPosition = source.getBindingAdapterPosition(); int toPosition = target.getBindingAdapterPosition(); if (fromPosition < data.size() && toPosition < data.size()) { Collections.swap(data, fromPosition, toPosition); notifyItemMoved(fromPosition, toPosition); } onItemClear(source); } @Override public void onItemSelect(RecyclerView.ViewHolder source) { source.itemView.setScaleX(1.2f); source.itemView.setScaleY(1.2f); } @Override public void onItemClear(RecyclerView.ViewHolder source) { source.itemView.setScaleX(1.0f); source.itemView.setScaleY(1.0f); } }
通过让Adapter实现ItemDragTouchHelper接口,进行具体的逻辑逻辑处理。
// 表格布局,3列 GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3); recyclerView.setLayoutManager(gridLayoutManager); // 默认动画 recyclerView.setItemAnimator(new DefaultItemAnimator()); // 设置item偏移量 recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); // 边距16 outRect.set(16, 16, 16, 16); } }); DragAdapter dragAdapter = new DragAdapter(this); recyclerView.setAdapter(dragAdapter); // 适配器添加拖拽回调 ItemTouchHelper.Callback callback = new ItemDragTouchHelperCallback(dragAdapter); ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback); // 为recyclerView添加拖拽功能 itemTouchHelper.attachToRecyclerView(recyclerView);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。