美文网首页
RecyclerView 使用ItemTouchHelper实现

RecyclerView 使用ItemTouchHelper实现

作者: GODANDDEVIL | 来源:发表于2020-03-31 16:39 被阅读0次

    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

    相关文章

      网友评论

          本文标题:RecyclerView 使用ItemTouchHelper实现

          本文链接:https://www.haomeiwen.com/subject/gfiquhtx.html