RecyclerView 使用ItemTouchHelper实现

2020-03-31  本文已影响0人  GODANDDEVIL

ItemTouchHelper的核心在于ItemTouchHelper.Callback接口。temTouchHelper.Callback中几个比较重要的方法:

getSwipeThreshold() (返回值表示所能够接受的侧滑滑动的最大距离,当我们侧滑的距离大于该方法的返回值时,就会触发侧滑删除的操作。如果是自定义了删除按钮进行点击来执行删除item操作,因为该返回值表示百分比,那么我们只要把值设置成大于1就可以使得无论侧滑多少都不会触发侧滑删除这个操作了)
getSwipeEscapeVelocity() (侧滑的速度大于该方法的返回值也会触发侧滑删除的操作,如果是自定义删除按钮,设置值同上)
onChildDraw() (该方法在ItemView进行滑动时会回调,这里的滑动包括:1、手指滑动;2、ItemView的位移动画。可以根据isCurrentlyActive参数来判断是手指滑动还是动画滑动)
clearView() (该方法在ItemView滑动完成之后会回调,想要实现侧滑ItemView停在某种状态,判断手指松开时ItemView的滑动距离是否大于我们设置的阈值(是否显示删除按钮的阈值),如果大于的话,只滑动到指定的位置,如果小于的话,就回到初始位置)

具体实现:
1、创建一个Activity,RecyclerActivity.java:

//import android.graphics.Canvas;
import android.os.Bundle;
import android.view.View;

import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

//import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

public class RecyclerActivity extends FatherActivity{

    private String[] titles = {"china","america","apple","canada","water","flower","candy","lisa","jon","teacher","student","moon","second","dog"};
    private String[] contents = {"This is china","This is america","This is apple","This is canada","This is water","This is water","This is water","This is water","This is water","This is water","This is water","This is water","This is water","This is water"};
    private int[] leftImages = {R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher};

    List<RecyclerModel> list;//数据源
    RecyclerView recyclerView;
    CustomRecyclerViewAdapter customRecyclerViewAdapter;
//    RecyclerModel recyclerModel;//保存正在拖动的item所对应的对象
//    String dragStartTag;//记录recyclerview拖动item的起始位置

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler);

        initView();
    }

    void initView(){
        //加载数据
        list = new ArrayList<>();
        for(int i = 0; i < titles.length; i++){
            RecyclerModel model = new RecyclerModel(leftImages[i],titles[i],contents[i]);
            list.add(model);
        }
        customRecyclerViewAdapter = new CustomRecyclerViewAdapter(list);
        recyclerView = findViewById(R.id.recycler_recyclerview);
        //设置adapter
        recyclerView.setAdapter(customRecyclerViewAdapter);
        //加载LayoutManager
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        //初始化ItemTouchHelper
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new CustomItemTouchHelperCallback(GeneralFunction.dpToPx(this, 60),list));
        itemTouchHelper.attachToRecyclerView(recyclerView);


//        //拖动起始记录值与拖动的item暂存对象初始值为空
//        recyclerModel = null;
//        dragStartTag = null;
//        ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
//            //itemView可滑动的最大阈值(当滑动距离超过最大阈值,松开手指时会回弹到阈值的位置)
//            int mDefaultScrollX = GeneralFunction.dpToPx(RecyclerActivity.this,64);
//            /**
//             *这个方法用于让RecyclerView拦截上下滑动和左右滑动的事件
//             * makeMovementFlags(dragFlags, swipeFlags);dragFlags是上下方向的滑动 swipeFlags是左右方向上的滑动
//             */
//            @Override
//            public int getMovementFlags(@NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder viewHolder) {
//                return makeMovementFlags(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT);
//            }
//
//            /**
//             * 针对drag状态,在canDropOver()返回true时,会调用该方法
//             * 这里需要我们自己处理拖动后互换位置的逻辑
//             */
//            @Override
//            public boolean onMove(@NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder viewHolder, @NotNull RecyclerView.ViewHolder target) {
//                if(recyclerView.getAdapter() != null){//拖动过程中不断更换位置
//                    recyclerView.getAdapter().notifyItemMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition());
//                }
//                return true;
//            }
//
//            /**
//             * 针对drag状态,当前target对应的item是否允许移动
//             * 我们一般用drag来做一些换位置的操作,就是当前对应的target对应的Item可以移动
//             */
//            @Override
//            public boolean canDropOver(@NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder current, @NotNull RecyclerView.ViewHolder target) {
//                return true;
//            }
//
//            /**
//             * 针对drag状态,当drag ItemView跟底下ItemView重叠时,可以给drag ItemView设置一个Margin值
//             * 让重叠不容易发生,相当于增大了drag Item的区域
//             */
//            @Override
//            public int getBoundingBoxMargin() {
//                return 0;
//            }
//
//            /**
//             * 针对drag状态,当滑动超过多少就可以出发onMove()方法(这里指onMove()方法的调用,并不是随手指移动的View)
//             */
//            public float getMoveThreshold(@NotNull RecyclerView.ViewHolder viewHolder) {
//                return .5f;
//            }
//
//            /**
//             * 针对drag状态,在drag的过程中获取drag itemView底下对应的ViewHolder(一般不用我们处理直接super就好了)
//             */
//            public RecyclerView.ViewHolder chooseDropTarget(@NotNull RecyclerView.ViewHolder selected,
//                                                            @NotNull List<RecyclerView.ViewHolder> dropTargets,
//                                                            int curX,
//                                                            int curY) {
//                return super.chooseDropTarget(selected, dropTargets, curX, curY);
//            }
//
//            /**
//             * 当onMove return true的时候调用(一般不用我们自己处理,直接super就好)
//             */
//            public void onMoved(@NotNull final RecyclerView recyclerView,
//                                @NotNull final RecyclerView.ViewHolder viewHolder,
//                                int fromPos,
//                                @NotNull final RecyclerView.ViewHolder target,
//                                int toPos,
//                                int x,
//                                int y) {
//                super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
//            }
//
//            /**
//             * 针对swipe和drag状态,当一个item view在swipe、drag状态结束的时候调用
//             * drag状态:当手指释放的时候会调用
//             * swipe状态:当item从RecyclerView中删除的时候调用,一般我们会在onSwiped()函数里面删除掉指定的item view
//             */
//            public void clearView(@NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder viewHolder) {
//                super.clearView(recyclerView, viewHolder);
//
//                if (recyclerView.getAdapter()!=null){
//                    //dragStartTag和recyclerModel都不为空则是drag状态
//                    if (dragStartTag!=null && recyclerModel!=null){
//                        viewHolder.itemView.setBackgroundColor(getResources().getColor(R.color.colorSelect));//item样式恢复原样
//                        int endLocation = viewHolder.getAdapterPosition();//获取正在拖动的item对象的最终目标位置
//                        int start = Integer.parseInt(dragStartTag);//获取已记录的item起始位置
//                        list.remove(start);//先删除数组里相对应的正在拖动的item对象
//                        list.add(endLocation,recyclerModel);//在数组对应的最终目标位置插入先前保存的item对象
//                        if (start>endLocation){
//                            //起始位置大于目标位置,那么recyclerView局部刷新范围则是,从目标位置开始到起始位置结束范围内刷新数据
//                            recyclerView.getAdapter().notifyItemRangeChanged(endLocation,start-endLocation+1);
//                        }else if (start<endLocation){
//                            //起始位置小于目标位置,那么recyclerView局部刷新范围则是,从起始位置开始到目标位置结束范围内刷新数据
//                            recyclerView.getAdapter().notifyItemRangeChanged(start,endLocation-start+1);
//                        }
//                        //拖动结束最后要将记录值与暂存的item对象置为空
//                        dragStartTag = null;
//                        recyclerModel = null;
//
//                    }
////                else {//swipe状态
////                    if (viewHolder.itemView.getScrollX() >= mDefaultScrollX) {
////                        viewHolder.itemView.scrollTo(mDefaultScrollX, 0);//让item最终偏移量为阈值即可显示删除按钮
////                    } else {
////                        //往右滑的时候直接恢复初始位置(此时getScrollX()永远小于阈值,因为往右滑偏移量是负值)
////                        viewHolder.itemView.scrollTo(0, 0);
////                    }
////                }
//                }
//
//            }
//
//            /**
//             * 针对swipe和drag状态,整个过程中一直会调用这个函数,随手指移动的view就是在super里面做到的(和ItemDecoration里面的onDraw()函数对应)
//             */
//            public void onChildDraw(@NotNull Canvas c, @NotNull RecyclerView recyclerView, @NotNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
//                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
//
//                //当处于Swipe状态时
//                if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
//                    //dX的值,表示手指滑动的距离,往右滑动为正,往左为负
//                    // getScrollX()的值,表示itemView的偏移量,往右是负,往左是正
//                    if (isCurrentlyActive) {//手指滑动时
//                        // 基于当前位置的偏移
//                        viewHolder.itemView.scrollTo( (int)-dX, 0);
//                    } else {//手指松开时,因为我们设置了侧滑距离无论多大也不会删除item,所以手指松开时,itemView会回滚
//                        //判断ItemView的偏移量是否大于给定阈值,如果大于让itemView的偏移量最终停留在阈值,显示删除按钮
//                        if (viewHolder.itemView.getScrollX() >= mDefaultScrollX) {
//                            viewHolder.itemView.scrollTo(mDefaultScrollX, 0);//让item最终偏移量为阈值即可显示删除按钮
//                        } else {
//                            //往右滑的时候直接恢复初始位置(此时getScrollX()永远小于阈值,因为往右滑偏移量是负值)
//                            viewHolder.itemView.scrollTo(0, 0);
//                        }
//                    }
//                }
//
//            }
//
//            /**
//             * 针对swipe和drag状态,整个过程中一直会调用这个函数(和ItemDecoration里面的onDrawOver()函数对应)
//             * 这个函数提供给我们可以在RecyclerView的上面再绘制一层东西,比如绘制一层蒙层啥的
//             */
//            public void onChildDrawOver(@NotNull Canvas c, @NotNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
//                super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
//            }
//
//            /**
//             * 针对swipe和drag状态,当手指离开之后,view回到指定位置动画的持续时间(swipe可能是回到原位,也有可能是swipe掉)
//             */
//            public long getAnimationDuration(@NotNull RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
//                return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
//            }
//
//            /**
//             * 针对drag状态,当itemView滑动到RecyclerView边界的时候(比如下面边界的时候),RecyclerView会scroll,
//             * 同时会调用该函数去获取scroller距离(不用我们处理 直接super)
//             */
//            public int interpolateOutOfBoundsScroll(@NotNull RecyclerView recyclerView,
//                                                    int viewSize,
//                                                    int viewSizeOutOfBounds,
//                                                    int totalSize,
//                                                    long msSinceStartScroll) {
//                return super.interpolateOutOfBoundsScroll(recyclerView, viewSize, viewSizeOutOfBounds, totalSize, msSinceStartScroll);
//            }
//
//            /**
//             * 针对swipe和drag状态,当swipe或者drag对应的ViewHolder改变的时候调用
//             * 我们可以通过重写这个函数获取到swipe、drag开始和结束时机,viewHolder 不为空的时候是开始,空的时候是结束
//             * 即处于拖动或者滑动时调用
//             */
//            public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
//                super.onSelectedChanged(viewHolder, actionState);
//                //当item开始拖动时,需要处理的逻辑
//                if(actionState == ItemTouchHelper.ACTION_STATE_DRAG && viewHolder!=null){
//                    viewHolder.itemView.setBackgroundColor(getResources().getColor(R.color.colorModel));//设置item拖动时样式
//                    int startLocation = viewHolder.getAdapterPosition();//获取正在拖动的item的起始位置
//                    dragStartTag = String.valueOf(startLocation);//记录起始位置
//                    recyclerModel = list.get(startLocation);//将正在拖动的item对象取出暂时保存
//                }
//            }
//
//            /**
//             * 针对swipe状态,是否允许swipe(滑动)操作
//             */
//            public boolean isItemViewSwipeEnabled() {
//                return true;
//            }
//
//            /**
//             * 针对swipe状态,swipe滑动的位置超过了百分之多少就消失
//             */
//            public float getSwipeThreshold(@NotNull RecyclerView.ViewHolder viewHolder) {
//                return Integer.MAX_VALUE;//设置成足够大的值,就可以达到滑动到item不可见也不会消失的效果
//            }
//
//            /**
//             * 针对swipe状态,swipe的逃逸速度,换句话说就算没达到getSwipeThreshold设置的距离,达到了这个逃逸速度item也会被swipe消失掉
//             */
//            public float getSwipeEscapeVelocity(float defaultValue) {
//                return Integer.MAX_VALUE;//设置成足够大的值,就可以使得无论逃逸速度有多快也不会消失的效果
//            }
//
//            /**
//             * 针对swipe状态,swipe滑动的阻尼系数,设置最大滑动速度
//             */
//            public float getSwipeVelocityThreshold(float defaultValue) {
//                return defaultValue;
//            }
//
//            /**
//             * 针对swipe状态,swipe 到达滑动消失的距离回调函数,一般在这个函数里面处理删除item的逻辑
//             * 确切的来讲是swipe item滑出屏幕动画结束的时候调用
//             */
//            public void onSwiped(@NotNull RecyclerView.ViewHolder viewHolder, int direction) { }
//
//        });
//        helper.attachToRecyclerView(recyclerView);

    }

    public void recycler_backClick(View view){
        finish();
    }

}

2、Activity的布局文件,activity_recycler.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".RecyclerActivity">

    <ImageView
        android:id="@+id/recycler_actionBar_bg"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:background="@color/colorModel"/>

    <ImageView
        android:id="@+id/recycler_back_bt"
        android:layout_width="25dp"
        android:layout_height="25dp"
        app:layout_constraintBottom_toBottomOf="@+id/recycler_actionBar_bg"
        app:layout_constraintLeft_toLeftOf="@+id/recycler_actionBar_bg"
        android:layout_marginLeft="5dp"
        android:layout_marginBottom="7dp"
        android:padding="3dp"
        android:src="@mipmap/back"
        android:onClick="recycler_backClick"/>

    <TextView
        android:id="@+id/recycler_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="@+id/recycler_actionBar_bg"
        app:layout_constraintBottom_toBottomOf="@+id/recycler_actionBar_bg"
        app:layout_constraintRight_toRightOf="@+id/recycler_actionBar_bg"
        android:layout_marginBottom="5dp"
        android:text="@string/RecyclerActivity_title"
        android:textColor="@color/colorWhite"
        android:textSize="12pt"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_recyclerview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@+id/recycler_actionBar_bg"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginTop="50dp"
        android:layout_marginLeft="45dp"
        android:layout_marginRight="45dp"
        android:layout_marginBottom="50dp"
        android:background="@color/colorWhite"/>


</androidx.constraintlayout.widget.ConstraintLayout>

3、创建一个对象模型类,RecyclerModel.java:

class RecyclerModel {
    int leftImage;
    String title;
    String content;
    RecyclerModel(int leftImage,String title,String content){
        this.leftImage = leftImage;
        this.title = title;
        this.content = content;
    }
}

4、创建RecyclerView的item布局,recyclerview_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@color/colorSelect"
    android:layout_marginTop="1dp"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ImageView
        android:id="@+id/recycler_item_leftImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_margin="5dp"/>

    <TextView
        android:id="@+id/recycler_item_title"
        android:layout_width="0dp"
        android:layout_height="22dp"
        app:layout_constraintLeft_toRightOf="@+id/recycler_item_leftImage"
        app:layout_constraintTop_toTopOf="@+id/recycler_item_leftImage"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginTop="5dp"
        android:textColor="@color/colorWhite"/>

    <TextView
        android:id="@+id/recycler_item_content"
        android:layout_width="0dp"
        android:layout_height="22dp"
        app:layout_constraintLeft_toRightOf="@+id/recycler_item_leftImage"
        app:layout_constraintBottom_toBottomOf="@+id/recycler_item_leftImage"
        app:layout_constraintRight_toRightOf="parent"
        android:textColor="@color/colorWhite"/>

    <TextView
        android:id="@+id/recycler_item_delete"
        android:layout_width="64dp"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toRightOf="@+id/recycler_item_title"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:text="@string/Delete"
        android:gravity="center"
        android:background="@color/colorRed"/>

</androidx.constraintlayout.widget.ConstraintLayout>

5、创建Adapter,CustomRecyclerViewAdapter.java:

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;


public class CustomRecyclerViewAdapter extends RecyclerView.Adapter<CustomRecyclerViewAdapter.CustomViewHolder>{

    private List<RecyclerModel> list;
    CustomRecyclerViewAdapter(List<RecyclerModel> list){
        this.list = list;
    }

    @NonNull
    @Override
    public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item,parent,false);
        return new CustomViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
        RecyclerModel model = list.get(position);
        holder.leftImageView.setImageResource(model.leftImage);
        holder.titleTextView.setText(model.title);
        holder.contentTextView.setText(model.content);
        //删除按钮点击事件处理
        holder.deleteTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                list.remove(holder.getAdapterPosition());
                notifyItemRemoved(holder.getAdapterPosition());//更新数据
                holder.itemView.setScrollX(0);//最后要将偏移量归零,防止复用产生的问题
            }
        });
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.v("position","--------"+holder.getAdapterPosition());
            }
        });
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    static class CustomViewHolder extends RecyclerView.ViewHolder{
        private ImageView leftImageView;
        private TextView titleTextView;
        private TextView contentTextView;
        private TextView deleteTextView;
        CustomViewHolder(@NonNull View itemView) {
            super(itemView);
            leftImageView = itemView.findViewById(R.id.recycler_item_leftImage);
            titleTextView = itemView.findViewById(R.id.recycler_item_title);
            contentTextView = itemView.findViewById(R.id.recycler_item_content);
            deleteTextView = itemView.findViewById(R.id.recycler_item_delete);
        }
    }

}

6、创建一个继承自ItemTouchHelper.Callback的类,CustomItemTouchHelperCallback.java:

import android.graphics.Canvas;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class CustomItemTouchHelperCallback extends ItemTouchHelper.Callback {
    private final int mDefaultScrollX;//itemView可滑动的最大阈值(当滑动距离超过最大阈值,松开手指时会回弹到阈值的位置)
    //拖动起始记录值与拖动的item暂存对象初始值要置为空
    private RecyclerModel recyclerModel = null;
    private String dragStartTag = null;
    //传入的数据源
    private final List<RecyclerModel> list;
    //CustomItemTouchHelperCallback构造方法,传入默认的最大偏移量和数据源
    CustomItemTouchHelperCallback(int defaultScrollX,List<RecyclerModel> list) {
        mDefaultScrollX = defaultScrollX;
        this.list = list;
    }

    /**
     *这个方法用于让RecyclerView拦截上下滑动和左右滑动的事件
     * makeMovementFlags(dragFlags, swipeFlags);dragFlags是上下方向的滑动 swipeFlags是左右方向上的滑动
     */
    @Override
    public 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);
    }

    /**
     * 针对drag状态,在canDropOver()返回true时,会调用该方法
     * 这里需要我们自己处理拖动后互换位置的逻辑
     */
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        if(recyclerView.getAdapter() != null){//拖动过程中不断更换位置
            recyclerView.getAdapter().notifyItemMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition());
        }
        return true;
    }

    /**
     * 针对swipe和drag状态,当一个item view在swipe、drag状态结束的时候调用
     * drag状态:当手指释放的时候会调用
     * swipe状态:当item从RecyclerView中删除的时候调用,一般我们会在onSwiped()函数里面删除掉指定的item view
     */
    @Override
    public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);

        if (recyclerView.getAdapter()!=null){
            //dragStartTag和recyclerModel都不为空则是drag状态
            if (dragStartTag!=null && recyclerModel!=null){
                viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getResources().getColor(R.color.colorSelect));//item样式恢复原样
                int endLocation = viewHolder.getAdapterPosition();//获取正在拖动的item对象的最终目标位置
                int start = Integer.parseInt(dragStartTag);//获取已记录的item起始位置
                list.remove(start);//先删除数组里相对应的正在拖动的item对象
                list.add(endLocation,recyclerModel);//在数组对应的最终目标位置插入先前保存的item对象
                if (start>endLocation){
                    //起始位置大于目标位置,那么recyclerView局部刷新范围则是,从目标位置开始到起始位置结束范围内刷新数据
                    recyclerView.getAdapter().notifyItemRangeChanged(endLocation,start-endLocation+1);
                }else if (start<endLocation){
                    //起始位置小于目标位置,那么recyclerView局部刷新范围则是,从起始位置开始到目标位置结束范围内刷新数据
                    recyclerView.getAdapter().notifyItemRangeChanged(start,endLocation-start+1);
                }
                //拖动结束最后要将记录值与暂存的item对象置为空
                dragStartTag = null;
                recyclerModel = null;

            }
//            else {//swipe状态
//                if (viewHolder.itemView.getScrollX() >= mDefaultScrollX) {
//                    viewHolder.itemView.scrollTo(mDefaultScrollX, 0);//让item最终偏移量为阈值即可显示删除按钮
//                } else {
//                    //往右滑的时候直接恢复初始位置(此时getScrollX()永远小于阈值,因为往右滑偏移量是负值)
//                    viewHolder.itemView.scrollTo(0, 0);
//                }
//            }
        }


    }

    /**
     * 针对swipe和drag状态,整个过程中一直会调用这个函数,随手指移动的view就是在super里面做到的(和ItemDecoration里面的onDraw()函数对应)
     */
    @Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        //dX的值,表示手指滑动的距离,往右滑动为正,往左为负
        // getScrollX()的值,表示itemView的偏移量,往右是负,往左是正
        if (isCurrentlyActive) {//手指滑动时
            // 基于当前位置的偏移
            viewHolder.itemView.scrollTo( (int)-dX, 0);
        } else {//手指松开时,因为我们设置了侧滑距离无论多大也不会删除item,所以手指松开时,itemView会回滚
            //判断ItemView的偏移量是否大于给定阈值,如果大于让itemView的偏移量最终停留在阈值,显示删除按钮
            if (viewHolder.itemView.getScrollX() >= mDefaultScrollX) {
                viewHolder.itemView.scrollTo(mDefaultScrollX, 0);//让item最终偏移量为阈值即可显示删除按钮
            } else {
                //往右滑的时候直接恢复初始位置(此时getScrollX()永远小于阈值,因为往右滑偏移量是负值)
                viewHolder.itemView.scrollTo(0, 0);
            }
        }
    }

    /**
     * 针对swipe和drag状态,当swipe或者drag对应的ViewHolder改变的时候调用
     * 我们可以通过重写这个函数获取到swipe、drag开始和结束时机,viewHolder 不为空的时候是开始,空的时候是结束
     * 即处于拖动或者滑动时调用
     */
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        super.onSelectedChanged(viewHolder, actionState);

        //当item开始拖动时,需要处理的逻辑
        if(actionState == ItemTouchHelper.ACTION_STATE_DRAG && viewHolder!=null){
            //先将拖动起始记录值与拖动的item暂存对象初始值置为空
            dragStartTag = null;
            recyclerModel = null;
            viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getResources().getColor(R.color.colorModel));//设置item拖动时样式
            int startLocation = viewHolder.getAdapterPosition();//获取正在拖动的item的起始位置
            dragStartTag = String.valueOf(startLocation);//记录起始位置
            recyclerModel = list.get(startLocation);//将正在拖动的item对象取出暂时保存
        }
    }

    /**
     * 针对swipe状态,swipe滑动的位置超过了百分之多少就消失
     */
    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        return Integer.MAX_VALUE;
    }

    /**
     * 针对swipe状态,swipe的逃逸速度,换句话说就算没达到getSwipeThreshold设置的距离,达到了这个逃逸速度item也会被swipe消失掉
     */
    @Override
    public float getSwipeEscapeVelocity(float defaultValue) {
        return Integer.MAX_VALUE;//设置成足够大的值,就可以使得无论逃逸速度有多快也不会消失的效果
    }

    /**
     * 针对swipe状态,swipe 到达滑动消失的距离回调函数,一般在这个函数里面处理删除item的逻辑
     * 确切的来讲是swipe item滑出屏幕动画结束的时候调用
     */
    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { }

}

转自:
https://www.jianshu.com/p/abedfa1d6dd1

上一篇下一篇

猜你喜欢

热点阅读