Android-------RecycleView自定义拖拽、侧滑的实现

Android-------RecycleView自定义拖拽、侧滑的实现

关于recycleView的拖拽和侧滑的实现,android原生已经为我们提供了实现方法,个人认为原生实现的方法其实已经很强大了,对于很多功能都是适用的,而且实现方法很简单。尤其是它带的拖拽功能非常好,动画也很流畅,效果很好。实现方法如下:

 ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {

            @Override
            public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                //控制view可移动操作方向方向
                final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
                        ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                final int swipeFlags = 0;
                return makeMovementFlags(dragFlags, swipeFlags);
            }

            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                //当拖拽移动交换
                int fromPosition = viewHolder.getAdapterPosition();
                int toPosition = target.getAdapterPosition();
                Collections.swap(list, fromPosition, toPosition);
                adapter.addData(list);
                adapter.notifyItemMoved(fromPosition, toPosition);
                return false;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                //当侧滑到一定程度时删除
                adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
            }

            @Override
            public boolean isLongPressDragEnabled() {
                //是否长按
                return true;
            }

            @Override
            public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
                //可以在选择的时候做一些选中改变
                viewHolder.itemView.setBackgroundColor(0xf0f0f0);
            }

            @Override
            public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                //当对某个view操作完后  也就是手松开后  如果侧滑,拖拽时做出了颜色的改变什么的等等,在这里使它复原,防止复用这个view时显示不对
                super.clearView(recyclerView, viewHolder);
            }

            @Override
            public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
                // 当对view进行拖拽,侧滑的过程中不断调用这个函数

                //仅对侧滑状态下的效果做出改变
                if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
                    //在这里做一些操作可以自定义侧滑
                }
                //仅对拖拽状态下的效果做出改变
                if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
                }
                super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            }
        });
        mItemTouchHelper.attachToRecyclerView(binding.rvList1);

因为我个人比较想巩固自定义view,动画等方面的知识,所以我没有引用Android原生自带的拖拽功能,而是通过实现重写RecyclerView.OnItemTouchListener方法来自定义这些功能。RecyclerView.OnItemTouchListener不是对item的监听,而是对recycleView触摸事件的监听,也就是说是以recycleView为中心,以recycleView建立的坐标系。

具体如何实现我就不具体介绍了,代码的注释很详细,讲明了流程,直接上代码。

item_expand

  • <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <LinearLayout
            android:id="@+id/view_root"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/gray_f0"
            android:orientation="horizontal"
            android:paddingBottom="1dp">
    
            <LinearLayout
                android:id="@+id/view_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/pink"
                android:gravity="center_vertical"
                android:orientation="horizontal">
    
                <ImageView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_marginLeft="10dp"
                    android:scaleType="fitXY"
                    android:src="@mipmap/example"
                    android:visibility="visible" />
    
                <TextView
                    android:id="@+id/tv_content"
                    style="@style/title_b"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:padding="15dp" />
            </LinearLayout>
    
            <LinearLayout
                android:id="@+id/view_operate"
                android:layout_width="240dp"
                android:layout_height="match_parent"
                android:background="@color/white"
                android:orientation="horizontal">
    
                <TextView
                    android:id="@+id/tv_look"
                    style="@style/body_w"
                    android:layout_width="80dp"
                    android:layout_height="match_parent"
                    android:background="@color/green"
                    android:gravity="center"
                    android:text="查看" />
    
                <TextView
                    android:id="@+id/tv_delete"
                    style="@style/body_w"
                    android:layout_width="80dp"
                    android:layout_height="match_parent"
                    android:background="@color/gray"
                    android:gravity="center"
                    android:text="删除" />
    
                <TextView
                    android:id="@+id/tv_jump"
                    style="@style/body_w"
                    android:layout_width="80dp"
                    android:layout_height="match_parent"
                    android:background="@color/blue"
                    android:gravity="center"
                    android:text="跳转" />
    
            </LinearLayout>
        </LinearLayout>
    </layout>
    
    ExpandAdapter
  • 
    public class ExpandAdapter extends BaseRecycleViewAdapter<String> {
    
        public ExpandAdapter(Context context) {
            super(context);
        }
    
        @Override
        public ViewDataBinding createView(ViewGroup parent) {
            ItemExpandBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.item_expand, parent, false);
            BaseBindingViewHolder holder = new BaseBindingViewHolder(binding);
            binding.tvDelete.setOnClickListener(this);
            binding.tvJump.setOnClickListener(onClickListener);
            binding.tvLook.setOnClickListener(onClickListener);
            return binding;
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            super.onBindViewHolder(holder, position);
            BaseBindingViewHolder viewHolder = (BaseBindingViewHolder) holder;
            ItemExpandBinding binding = (ItemExpandBinding) viewHolder.binding;
            binding.tvLook.setTag(position);
            binding.tvJump.setTag(position);
            binding.tvDelete.setTag(position);
            binding.tvContent.setText("" + list.get(position));
    
        }
    
        View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = (int) v.getTag();
                switch (v.getId()) {
                    case R.id.tv_delete:
                        ToastUtils.ViewToast(context, "删除");
                        break;
                    case R.id.tv_look:
                        ToastUtils.ViewToast(context, "查看");
                        break;
                    case R.id.tv_jump:
                        ToastUtils.ViewToast(context, "跳转");
                        break;
                }
    
            }
        };
    
        /**
         * 获取侧滑的宽度
         *
         * @param view
         * @return
         */
        public int getExpandWidth(View view) {
            if (view != null) {
                View expandView = view.findViewById(R.id.view_operate);
                return expandView.getLayoutParams().width;
            } else {
                return 0;
            }
        }
    }
    
    RecycleViewSlideActivity
  • 
    
    public class RecycleViewSlideActivity extends BaseActivity {
        ExpandAdapter adapter;
        ActivityExampleViewBinding binding;
        private ArrayList<String> list = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            binding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.activity_example_view, getParentView(), false);
            setMyContentView(binding.getRoot(), "测试");
            initView();
            initData();
        }
    
        @Override
        public void initView() {
            super.initView();
            list.add("0\n人生若只如初见,何事秋风悲画扇。 \n等闲变却故人心,却道故人心易变。 \n骊山语罢清宵半,泪雨霖铃终不怨。 \n何如薄幸锦衣郎,比翼连枝当日愿。");
            list.add("1\n明月多情应笑我,笑我如今,辜负春心,独自闲行独自吟。");
            list.add("2\n我是人间惆怅客, \n" +
                    "知君何事泪纵横, \n" +
                    "断肠声里忆平生。");
            list.add("3\n谁念西风独自凉?萧萧黄叶闭疏窗,沉思往事立残阳。 \n" +
                    "被酒莫惊春睡重,赌书消得泼茶香,当时只道是寻常。");
            list.add("4\n一生一代一双人,争教两处销魂。相思相望不相亲,天为谁春?");
            list.add("5\n浮生如此,别多会少,不如莫遇。");
            list.add("6\n回廊一寸相思地, \n" +
                    "落月成孤倚。 \n" +
                    "背灯和月就花阴, \n" +
                    "已是十年踪迹十年心。");
            list.add("7\n明月多情应笑我,笑我如今。 \n" +
                    "辜负春心,独自闲行独自吟。 \n" +
                    "近来怕说当时事,结遍兰襟。 \n" +
                    "月浅灯深,梦里云归何处寻?");
            list.add("8\n人生若只如初见,何事秋风悲画扇?");
            list.add("9\n山一程,水一程,身向榆关那畔行,夜深千帐灯。 \n" +
                    "风一更,雪一更,聒碎乡心梦不成,故园无此声。");
            list.add("10\n肠断月明红豆蔻,月似当时,人似当时否?   ");
    
            RecycleViewTool.setRecycleViewVertical(this, binding.rvList1);
            adapter = new ExpandAdapter(this);
            adapter.addData(list);
            binding.rvList1.setAdapter(adapter);
            binding.rvList1.addOnItemTouchListener(new RecycleViewOnItemTouchListener(adapter, onItemTouchCallBack, this));
           
        }
    
        RecycleViewOnItemTouchListener.OnItemTouchCallBack onItemTouchCallBack = new RecycleViewOnItemTouchListener.OnItemTouchCallBack() {
            @Override
            public void onDragFinish(View vew) {
    
            }
    
            @Override
            public void onSwipe(View view) {
    
            }
    
            @Override
            public boolean isLongPressEnable() {
                return true;
            }
    
            @Override
            public void onMove(int needExchangePosition, int targetPosition) {
                Collections.swap(list, targetPosition, needExchangePosition);
                adapter.addData(list);
                adapter.notifyItemMoved(targetPosition, needExchangePosition);
            }
    
            @Override
            public boolean onSelectedChanged(View view) {
                if (view != null && view instanceof LinearLayout) {
                    ((LinearLayout) view).getChildAt(0).setBackgroundColor(0xfffefefe);
                }
                return true;
            }
            @Override
            public boolean clearView(View view) {
                if (view != null && view instanceof LinearLayout) {
                    ((LinearLayout) view).getChildAt(0).setBackgroundColor(0xfffce4ec);
                }
                return false;
            }
    
        };
    }
    
    activity_example_view
  • <?xml version="1.0" encoding="utf-8"?>
    <layout>
    
        <LinearLayout 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"
            android:orientation="vertical">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv_list_1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
        </LinearLayout>
    </layout>
    
    RecycleViewOnItemTouchListener
  • 
    /**
     * 自定义recycleview的拖拽,侧滑
     */
    public class RecycleViewOnItemTouchListener implements RecyclerView.OnItemTouchListener {
        /**
         * 按下时X轴坐标
         */
        private float downPointX;
        /**
         * 按下时Y轴坐标
         */
        private float downPointY;
        /**
         * 上一个点的X轴坐标
         */
        private float startPointX;
        /**
         * 上一个点的Y轴坐标
         */
        private float startPointY;
        /**
         * 要进行拖动,侧滑的控件
         */
        private View mTargetView;
        /**
         * adapter
         */
        private ExpandAdapter adapter;
        /**
         * 是否有down事件
         */
        private boolean isDown = false;
        /**
         * 是否为长按
         */
        private boolean isLongPress;
        /**
         * 操作回调
         */
        private OnItemTouchCallBack callBack;
        /**
         * 上下文
         */
        private Context context;
        /**
         * 上一次交换的view
         */
        private View exchangeView = null;
        /**
         * 上一次滑动拖拽方向
         */
        private int exchangeDirection;//-1 没有交换过 0向上 1向下
        /**
         * 每一次拖动所进行的一系列动画
         */
        private ArrayList<Float> animations = new ArrayList<>();
        /**
         * 长按计时任务
         */
        private Timer timer;
        /**
         * 属性位移动画
         */
        private ObjectAnimator translateAnimation;
        /**
         * 是否正在交换
         */
        private boolean isExchanging;
        /**
         * 被拖拽的view在交换后它的top值或者bottom值,以此判断是否完成交换
         */
        private float needDistance;
    
        public RecycleViewOnItemTouchListener(ExpandAdapter adapter, OnItemTouchCallBack callBack, Context context) {
            this.adapter = adapter;
            this.callBack = callBack;
            this.context = context;
        }
    
        /**
         * 拦截true 表示拦截,调用onTouch   false表示不拦截,把时间传递给子View
         *
         * @return
         */
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            if (rv.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
                //列表为静止状态,可以操作
                switch (e.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //初始化
                        isExchanging = false;
                        mTargetView = null;
                        exchangeView = null;
                        exchangeDirection = -1;
                        animations.clear();
                        isDown = true;//记录此时按下了
                        isLongPress = false;
                        mTargetView = rv.findChildViewUnder(e.getX(), e.getY());
                        startPointX = e.getX();
                        startPointY = e.getY();
                        downPointX = e.getX();
                        downPointY = e.getY();
                        if (callBack.isLongPressEnable()) {
                            timer = new Timer();
                            timer.schedule(new TimerTask() {
                                @Override
                                public void run() {
                                    //长按100毫秒表示长按可移动
                                    isLongPress = true;
                                    Vibrator vibrator = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
                                    vibrator.vibrate(100);
                                }
                            }, ViewConfiguration.getLongPressTimeout());
                        }
                        return false;
                    case MotionEvent.ACTION_UP:
                        if (timer != null) {
                            timer.cancel();
                        }
                        if (isDown) {
                            //点击事件 不拦截
                            isDown = false;
                            mTargetView = null;
                            return false;
                        } else {
                            //上一个动作不是down,可能是move、cancel、outside
                            if (mTargetView == null) {
                                return false;
                            } else {
                                return judgeNeedIntercept();
                            }
                        }
                    case MotionEvent.ACTION_MOVE:
                        if (mTargetView == null) {
                            if (timer != null) {
                                timer.cancel();
                            }
                            isDown = false;
                            return false;
                        } else {
                            if (isDown) {
                                //前一个动作时按下
                                if (isLongPress) {
                                    //长按后再移动
                                    isDown = false;
                                    if (callBack != null) {
                                        if (callBack.onSelectedChanged(mTargetView)) {
                                            //可以拖拽
                                        } else {
                                            //不可以拖拽
                                            clearView();
                                            mTargetView = null;
                                            return false;
                                        }
                                    }
                                    return true;
                                } else {
                                    float distanceX = startPointX - e.getX();
                                    float distanceY = startPointY - e.getY();
                                    if (Math.max(Math.abs(distanceX), Math.abs(distanceY)) < 20) {
                                        //当从按下开始如果移动小于20,则任然视为按下,不能作为移动
                                        return false;
                                    } else {
                                        isDown = false;
                                        if (timer != null) {
                                            timer.cancel();
                                        }
                                        isLongPress = false;
                                        if (Math.abs(distanceX) > Math.abs(distanceY)) {
                                            //x方向的移动距离大于y方向的距离
                                            if (callBack != null) {
                                                if (callBack.onSelectedChanged(mTargetView)) {
                                                    //可以侧滑
                                                } else {
                                                    //不可以侧滑
                                                    clearView();
                                                    mTargetView = null;
                                                    return false;
                                                }
                                            }
                                            return true;
                                        } else {
                                            mTargetView = null;
                                            return false;
                                        }
                                    }
                                }
    
                            } else {
                                //x方向的移动距离大于y方向的距离
                                return true;
                            }
    
                        }
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_OUTSIDE:
                        if (timer != null) {
                            timer.cancel();
                        }
                        isDown = false;
                        if (mTargetView == null) {
                            return false;
                        } else {
                            return judgeNeedIntercept();
                        }
                }
            }
            return false;
        }
    
        /**
         * 在view被放开之后的状态ui还原
         */
        public void clearView() {
            if (mTargetView != null) {
                if (callBack != null) {
                    callBack.clearView(mTargetView);
                }
            }
        }
    
        /**
         * 判断是否拦截事件
         */
        public boolean judgeNeedIntercept() {
    
    //此处注明:view的scroll操作,其实是对view内部进行滚动,初始时状态偏移量为0   mTargetView.getScrollX() 获取的是绝对总偏移量,如果向左滚动,则偏移量为正,否则为负,,如果向上滚动,则偏移量为正,否则为负,就是偏移量=初始坐标-结束坐标
            //view.scrollTo()是指从初始状态移动多少,内部的值为偏移量值,是总偏移量,绝对值
            //view.scrollBy()是指从当前状态移动多少,内部的值为偏移量值,是部分偏移量,是相对值
            if (isLongPress) {
                //长按之后放开
                clearView();
                return true;
            } else {
                //判断移动距离
                if (mTargetView.getScrollX() == 0) {
                    //没有移动过 不作操作
                    clearView();
                    mTargetView = null;
                    return false;
                } else if (-mTargetView.getScrollX() == adapter.getExpandWidth(mTargetView)) {
                    //移动到底部,不作操作
                    clearView();
                    mTargetView = null;
                    return false;
                } else {
                    //需要做操作
                    return true;
                }
            }
        }
    
        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e) {
            if (isLongPress) {
                switch (e.getAction()) {
                    case MotionEvent.ACTION_MOVE:
                        if (isExchanging) {
                            if (exchangeDirection == 0) {
                                //向上
                                if (needDistance == mTargetView.getTop()) {
                                    //如果交换完成 则重新设置translation等的值,也可以进行动画
                                    isExchanging = false;
                                    mTargetView.setTranslationY(e.getY() - downPointY + exchangeView.getHeight());
    //                                mTargetView.setTranslationY(0);
                                    downPointY = e.getY();
                                    judgeIsExchange(e, rv);
                                }
                                //未完成则继续交换
                            } else if (exchangeDirection == 1) {
                                //向下
                                if (needDistance == mTargetView.getBottom()) {
                                    //如果在mTargetView在顶部的话,向下交换之后的时候就会看不到被交换的view,这个时候设置滚到被交换的viewde位置,可以防止这一操作
                                    ((RecyclerView) mTargetView.getParent()).scrollToPosition(((RecyclerView) mTargetView.getParent()).getChildAdapterPosition(mTargetView) - 1);
                                    isExchanging = false;
                                    mTargetView.setTranslationY(e.getY() - downPointY - exchangeView.getHeight());
    //                                mTargetView.setTranslationY(0);
                                    downPointY = e.getY();
                                    judgeIsExchange(e, rv);
                                }
                            }
    
                        } else {
                            judgeIsExchange(e, rv);
                        }
                        break;
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_OUTSIDE:
    
                        //取消所有拖拽动画,复原位置
                        if (translateAnimation != null) {
                            translateAnimation.cancel();
                            animations.clear();
                        }
                        mTargetView.setTranslationY(0);
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            mTargetView.setTranslationZ(0.0f);
                        }
                        if (mTargetView != null && callBack != null) {
                            callBack.onDragFinish(mTargetView);
                            clearView();
                        }
                        adapter.notifyDataSetChanged();
                        mTargetView = null;
                        exchangeView = null;
                        isExchanging = false;
                        exchangeDirection = -1;
                        break;
                }
            } else {
                switch (e.getAction()) {
                    case MotionEvent.ACTION_MOVE:
                        float distanceX = startPointX - e.getX();//获取需要再次滚动的偏移量
                        int mScrollX = (int) (mTargetView.getScrollX() + distanceX);//最终的偏移量
                        if (mScrollX >= adapter.getExpandWidth(mTargetView)) {//已经全部展开侧滑栏
                            mScrollX = adapter.getExpandWidth(mTargetView);
                        } else if (mScrollX <= 0) {//未展开侧滑栏
                            mScrollX = 0;
                        }
                        mTargetView.scrollTo(mScrollX, mTargetView.getScrollY());
                        startPointX = e.getX();
                        startPointY = e.getY();
                        break;
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_OUTSIDE:
                        if (mTargetView.getScrollX() > adapter.getExpandWidth(mTargetView) / 2) {
                            //移动的距离大于侧滑栏长度的一半,则把侧滑栏全部显示
                            mTargetView.scrollTo(adapter.getExpandWidth(mTargetView), mTargetView.getScrollY());
                        } else {
                            //隐藏侧滑栏
                            mTargetView.scrollTo(0, mTargetView.getScrollY());
                        }
                        if (mTargetView != null && callBack != null) {
                            callBack.onSwipe(mTargetView);
                        }
                        clearView();
                        mTargetView = null;
                        isLongPress = false;
                        break;
                }
            }
        }
    
        /**
         * 创建动画用于拖拽
         */
        public void createAnimation() {
            if (mTargetView != null && animations.size() > 0) {
                translateAnimation = ObjectAnimator.ofFloat(mTargetView, "translationY", mTargetView.getTranslationY(), mTargetView.getTranslationY() + animations.get(0));
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    mTargetView.setTranslationZ(0.1f);
                }
                translateAnimation.setDuration(0);
                translateAnimation.addListener(animatorListener);
                translateAnimation.start();
    //            ObjectAnimator translateZAnimation = ObjectAnimator.ofFloat(mTargetView, "translationZ", 0, 100);
    //            AnimatorSet animatorSet = new AnimatorSet();
    //            //使用play方法把两个动画拼接起来
    //            animatorSet.playTogether(translateAnimation, translateZAnimation);
    //            //时间
    //            animatorSet.setDuration(3000);
    //            //开始执行
    //            animatorSet.start();
    //            animatorSet.addListener(animatorListener);
            }
    
        }
    
        Animator.AnimatorListener animatorListener = new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }
    
            @Override
            public void onAnimationEnd(Animator animation) {
    
                if (animations.size() > 0) {
                    animations.remove(0);
                }
                if (animations.size() > 0) {
                    createAnimation();
                }
            }
    
    
            @Override
            public void onAnimationCancel(Animator animation) {
    
            }
    
            @Override
            public void onAnimationRepeat(Animator animation) {
    
            }
        };
    
        /**
         * 对每次移动进行操作判断
         */
        public void judgeIsExchange(MotionEvent e, RecyclerView rv) {
            //     每次移动,记录移动的距离,加入动画列表,当上一个位移动画完成时,完成当前位移动画
            if (animations.size() == 0) {
                animations.add(e.getY() - startPointY);
                createAnimation();
            } else {
                animations.add(e.getY() - startPointY);
            }
    
            //获取被拖拽view的位置
            int targetPosition = rv.getChildAdapterPosition(mTargetView);
            //记录移动方向
            int tempExchangeDirection;
            View view;
            if (e.getY() - startPointY > 0) {
                //向下移动
                tempExchangeDirection = 1;
                view = findChildViewUnder(mTargetView.getLeft(), mTargetView.getBottom() + e.getY() - downPointY, rv, tempExchangeDirection);
            } else {
                //向上移动
                tempExchangeDirection = 0;
                view = findChildViewUnder(mTargetView.getLeft(), mTargetView.getTop() + e.getY() - downPointY, rv, tempExchangeDirection);
            }
            //记录当前移动位置坐标
            startPointY = e.getY();
            startPointX = e.getX();
            //获取当前手指所在的View
    //       View view = findChildViewUnder(e.getX(), e.getY(), rv);
            int currentPosition = rv.getChildAdapterPosition(view);
    //注意:view进行属性动画或者补间动画的时候,view.getTop等值是不变的,任然是view未偏移之前的初始位置的getop值,也就是偏移只改变了translateY的值 mTargetView.getTranslationY()=当前坐标-初始未偏移之前的坐标=偏移量
            if (targetPosition != -1 && currentPosition != -1 && currentPosition != targetPosition) {
                if (tempExchangeDirection == 0) {
                    //向上
                    if (mTargetView.getTop() == view.getBottom()) {
                        //如果手指所在位置和被拖拽view的位置是上下相邻
                        if (mTargetView.getTop() + e.getY() - downPointY <= view.getTop()) {
                            //如果手指所在位置的view和被拖拽view的top是重合了,则交换位置
                            changeView(view, tempExchangeDirection, targetPosition, currentPosition);
                        }
                    } else if (mTargetView.getTop() > view.getBottom()) {
                        //如果手指所在view和被拖拽view的位置是不相邻,则被拖拽的view和手指所在view的下一个view交换
    
                        changeView(rv.getChildAt(currentPosition + 1 - ((LinearLayoutManager) rv.getLayoutManager()).findFirstVisibleItemPosition()), tempExchangeDirection, targetPosition, currentPosition + 1);
    
                    }
    
                } else {
                    //向下
                    if (mTargetView.getBottom() == view.getTop()) {
                        //如果手指所在位置和被拖拽view的位置是下上相邻
                        if (mTargetView.getBottom() + e.getY() - downPointY >= view.getBottom()) {
                            //如果手指所在位置的view和被拖拽view的bottom是重合了,则交换位置
                            changeView(view, tempExchangeDirection, targetPosition, currentPosition);
                        }
                    } else if (mTargetView.getBottom() < view.getTop()) {
                        //如果手指所在view和被拖拽view的位置是不相邻,则被拖拽的view和手指所在view的上一个view交换,
                        // 这里有一个Android的bug,rv.getChildAt(position)获取的并不是当前位置的view,这个position指的是那些可看见的view的数组的位置,即((LinearLayoutManager)rv.getLayoutManager()).findFirstVisibleItemPosition()在该列表里的位置为0
                        changeView(rv.getChildAt(currentPosition - 1 - ((LinearLayoutManager) rv.getLayoutManager()).findFirstVisibleItemPosition()), tempExchangeDirection, targetPosition, currentPosition - 1);
    
                    }
                }
            }
    
        }
    
        /**
         * 交换位置
         *
         * @param view
         * @param tempExchangeDirection 拖拽方向 0向上 1向下
         * @param needExchangePosition  被交换的位置
         * @param targetPosition        被拖拽的控件所在的位置
         */
        public void changeView(View view, int tempExchangeDirection, int targetPosition, int needExchangePosition) {
            //在一个方向上(向上或向下)不可能被拖拽的控件不可能和另一个控件先后两次交换
            if (exchangeView == null || !(exchangeView == view && tempExchangeDirection == exchangeDirection)) {
                exchangeView = view;
                exchangeDirection = tempExchangeDirection;//记录此时的拖拽方向和交换控件
                animations.clear();
                translateAnimation.cancel();
                isExchanging = true;
                if (exchangeDirection == 0) {
                    if (mTargetView.getTop() <= 0) {
                        needDistance = mTargetView.getTop();
                    } else {
                        needDistance = view.getTop();
                    }
                } else {
                    if (mTargetView.getTop() <= 0) {
                        needDistance = mTargetView.getBottom();
                    } else {
                        needDistance = view.getBottom();
                    }
                }
                if (callBack != null) {
                    callBack.onMove(needExchangePosition, targetPosition);
                }
    
            }
        }
    
        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    
        }
    
        /**
         * 拖拽时获取手指所在的位置对应的控件
         *
         * @param x
         * @param y
         * @param rv
         * @return
         */
    
        public View findChildViewUnder(float x, float y, RecyclerView rv) {
            View child;
            final int count = rv.getChildCount();
            for (int i = 0; i < count; i++) {
                child = rv.getChildAt(i);
                if (child != null) {
                    if (x >= child.getLeft()
                            && x <= child.getRight()
                            && y >= child.getTop()
                            && y <= child.getBottom()) {
                        return child;
                    }
                }
            }
            return null;
        }
    
        /**
         * 拖拽时获取此时被拖拽的view的左上角的所在的位置对应的控件
         *
         * @param x
         * @param y
         * @param rv
         * @return
         */
    
        public View findChildViewUnder(float x, float y, RecyclerView rv, int tempExchangeDirection) {
            View child;
            final int count = rv.getChildCount();
            for (int i = 0; i < count; i++) {
                child = rv.getChildAt(i);
                if (child != null) {
                    if (tempExchangeDirection == 0) {
                        if (x >= child.getLeft()
                                && x <= child.getRight()
                                && y >= child.getTop()
                                && y < child.getBottom()) {
                            return child;
                        }
                    } else {
                        if (x >= child.getLeft()
                                && x <= child.getRight()
                                && y > child.getTop()
                                && y <= child.getBottom()) {
                            return child;
                        }
                    }
    
                }
            }
            return null;
        }
    
        public interface OnItemTouchCallBack {
            /**
             * 当拖拽释放后
             *
             * @param vew 被拖拽的控件
             */
            void onDragFinish(View vew);
    
            /**
             * 当侧滑展开后
             *
             * @param view
             */
            void onSwipe(View view);
    
            /**
             * 是否支持长按
             *
             * @return true 可长按   false不看不可以长按
             */
            boolean isLongPressEnable();
    
            /**
             * 当拖拽移动交换的时候
             *
             * @param needExchangePosition 被交换的位置
             * @param targetPosition       被拖拽的控件所在的位置
             */
            void onMove(int needExchangePosition, int targetPosition);
    
            /**
             * 当长按或者侧滑的控件被选择时
             *
             * @param view 被选择的控件
             * @return
             */
            boolean onSelectedChanged(View view);
    
            /**
             * 手松开后的一些操作
             *
             * @param view
             * @return
             */
            boolean clearView(View view);
        }
    
    }
    

     

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值