跨多个RecyclerView拖动排序

来源:互联网 发布:linux 命令 ls l 编辑:程序博客网 时间:2024/05/21 09:46

先介绍一下本文出现的背景,项目中有这样一个需求,拖动一个列表的某一项排序或者拖动到另外一个列表中。

其效果如下图:

这里写图片描述

拖动排序在RecyclerView有现成的解决方案,配合ItemTouchHelper即可轻松实现。但是要将一个列表中的Item拖动到另一个列表中去,就不那么容易了。

先来看看这种跨界面实现由那些难点,我们先分析,再一个一个的解决。

  • 拖动视图的保存,ItemTouchHelper的实现思路是获取到长按的View后,对这个View做Translate位移,但是这样做的局限在于这个View就只能在它所属的RecyclerView中移动,超出的部分就被隐藏了。
  • 当拖动Item到边缘后,两个界面怎么切换,是使用系统的ViewPager还是自定义ViewGroup。
  • 在一个RecyclerView中拖动和跨多个拖动用到的策略是否一样。
  • 由于RecyclerView已经接收了触摸事件,那么怎么获取触摸信息,比如判断滑到边缘了,以及Item是否长按。

现在我们来一个一个的解决上面的问题:
1. 对于第一个问题,解决方法是当判断Item被长按后,将当前Item记录为一张图片,然后设置给一个隐藏的ImageView,对这个ImageView做Translate平移。这里需要额外费心的是这个ImageView与长按Item视图的重合以及显隐判断。
2. 如果使用ViewPager,由于要跨越两个page,那么触摸事件,保存的图片等都要交给其父控制器,还不如自定义一个ViewGroup。
3. 由于系统提供了在一个RecyclerView中拖动的Helper类,我们无需去解决拖动的起始位置这些,那何乐不为呢?所以,跨界面拖动用自己的实现。
4. 触摸point信息的获取:dispatchTouchEvent方法是最先到的,在我们自定义的ViewPager中重写该方法。在adapter中对itemview添加手势监听,获取到被长按的View。

下面来看代码实现:

(1) 自定义的父视图:

public class NewLinearLayout extends LinearLayout {    /*将触摸点坐标传递出去*/    private IGetX iGetX;    /*弹性滑动*/    private Scroller mScroller;    public NewLinearLayout(Context context) {        super(context);        init(context);    }    public NewLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public NewLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    /*initial*/    public void init(Context context){        mScroller = new Scroller(context);    }    @Override    public void computeScroll(){        super.computeScroll();        /*判断是否完成滑动*/        if(mScroller.computeScrollOffset()){            scrollTo(mScroller.getCurrX() , 0);            /*循环调用该方法*/            postInvalidate();        }    }    /*开启弹性滑动*/    public void beginScroll(int dx ){        mScroller.startScroll(mScroller.getCurrX() , 0 , dx , 0 , 1000);        /*调用computeScroll()方法*/        invalidate();    }    @Override    public boolean dispatchTouchEvent(MotionEvent event){        float dx = event.getX();        float dy = event.getY();        if(event.getAction() == MotionEvent.ACTION_MOVE)            iGetX.point(dx , dy);        return super.dispatchTouchEvent(event);    }    public void set(IGetX iGetX){        this.iGetX = iGetX;    }    public interface IGetX{        void point(float dx , float dy);    }}

(2) View转bitmap

    public Bitmap view2bitmap(View view) {        int width = view.getMeasuredWidth();        int height = view.getMeasuredHeight();        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);        view.draw(new Canvas(bitmap));        return bitmap;    }

(3) Adapter的实现

    private class Recycler1Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {        private ArrayList<String> mData;        public void setData(ArrayList<String> mData) {            this.mData = mData;        }        public void addData(ArrayList<String> mData) {            this.mData.addAll(mData);            notifyDataSetChanged();        }        @Override        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            View itemView = LayoutInflater.from(SpanDragActivity.this).inflate(R.layout.item_launch_title, null);            final Recycler1ViewHolder viewHolder = new Recycler1ViewHolder(itemView);            viewHolder.itemView.setOnTouchListener(new View.OnTouchListener() {                @Override                public boolean onTouch(View v, MotionEvent event) {                    mDetector.onTouchEvent(event);                    if(event.getAction() == MotionEvent.ACTION_DOWN){                        bitmap = null;                        TempItemView = viewHolder.itemView;                        startX = TempItemView.getLeft();                        startY = TempItemView.getTop();                    }                    /*恢复计点*/                    if(event.getAction() == MotionEvent.ACTION_UP){                        isFirstPoint = true;                    }                    return false;                }            });            return viewHolder;        }        @Override        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {            ((Recycler1ViewHolder) holder).mTv.setText(mData.get(position));        }        @Override        public int getItemCount() {            return mData.size();        }        /*create viewholder*/        class Recycler1ViewHolder extends RecyclerView.ViewHolder {            private TextView mTv;            public Recycler1ViewHolder(View itemView) {                super(itemView);                mTv = (TextView) itemView.findViewById(R.id.item_launch_title_tv_title);            }        }    }

(4) 滑动到边缘后触发的事件

        /*设置接口获取手指位置*/        activitySpanLl.set(new NewLinearLayout.IGetX() {            @Override            public void point(float dx , float dy) {                Log.v("out", "手指位置:" + dx);                if(isFirstPoint){                    firstX = dx;                    firstY = dy;                    isFirstPoint = false;                }                if(bitmap != null) {                    activitySpanImg.setTranslationX(dx-firstX+startX);                    activitySpanImg.setTranslationY(dy-firstY+startY);                }                if(dx >=800){                }                if (isFirstScroll)                    if (dx >= 1000) {                        activitySpanLl.beginScroll(1080);                        isFirstScroll = false;                        /*向右边滑动了,所以现在可以向左滑动了*/                        isFirstLeftScroll = true;                        int a = activitySpanLl.getScrollX();                        float b = activitySpanLl.getX();                    }                if(isFirstLeftScroll)                    if(dx <= 80){                        activitySpanLl.beginScroll(-1080);                        isFirstLeftScroll = false;                        /*向左边滑动了,所以现在可以向右滑动了*/                        isFirstScroll = true;                        int a = activitySpanLl.getScrollX();                        float b = activitySpanLl.getX();                    }            }        });
基本思路和重要的代码都在上面了,在实际项目中应用还需要对坐标,滑动等作出优化。

有更多问题留言交流。

1 0
原创粉丝点击