Recyclerview实现仿电脑文件夹自由拖拽

##Recyclerview 实现仿电脑文件夹自由拖拽

大家好,今天是我第一次写博客,希望能将学到的技术点记录起来,方便以后借鉴。不足之处,请指出,大家一起学习。
想实现和电脑拖拽文件夹一样的效果其实很简单,因为Recyclerview 本身就提供了类似的动画效果,我们只需将原来的动画效果改吧改吧就可以了。

##效果
这里写图片描述

1.创建Activity(Mistake_Homework_Activity ) 下面是XML布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_mistake__homework_"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    tools:context="com.daxiong.fun.function.homework.MistakeHomework.Mistake_Homework_Activity">
    <include
        android:id="@+id/layout_head"
        layout="@layout/main_header_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v7.widget.RecyclerView
        android:background="@color/white"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="5dp"
        android:layout_below="@+id/layout_head"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerView"/>

    <TextView
        android:text="编辑"
        android:textSize="16sp"
        android:id="@+id/tv_edit"
        android:layout_marginRight="5dp"
        android:layout_alignParentRight="true"
        android:padding="10dp"
        android:gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="50dp" />
</RelativeLayout>

##2.先定义一个回调接口
这个先放着,待会再用。

public interface CallbackItemTouch {
    /**
     * Called when an item has been dragged
     * @param oldPosition start position
     * @param newPosition end position
     */
    void itemTouchOnMove(RecyclerView.ViewHolder holder, int oldPosition, int newPosition,RecyclerView.ViewHolder target);
}

##3.重写 ItemTouchHelper.Callback的内部类
ItemTouchHelper这个类它继承了 RecyclerView.ItemDecoration。这是一个强大的帮助类。用来配合RecyclerView使用,ItemTouchHelper同一时刻只能支持两种效果:swipe、drag中的一种。分别用来实现RecyclerView里面item侧滑删除(swipe)效果或者item长按拖拽移动(drag)。

/**
 * Created by guo on 2018/7/24.
 */

public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback{
    CallbackItemTouch callbackItemTouch; // interface

    public MyItemTouchHelperCallback(CallbackItemTouch callbackItemTouch){
        this.callbackItemTouch = callbackItemTouch;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        return false; // swiped disabled
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    // movements drag 设置可自由拖动的方向
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT| ItemTouchHelper.RIGHT; 
        return makeFlag( ItemTouchHelper.ACTION_STATE_DRAG , dragFlags); 
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
 //当拖拽时的回调方法, callbackItemTouch就是我们刚刚写的回调接口啦,待会我们会在activity中重写这个子类。     
 callbackItemTouch.itemTouchOnMove(viewHolder,viewHolder.getAdapterPosition(),target.getAdapterPosition(),target); // information to the interface
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        // swiped disabled
    }
}

##4.Mistake_Homework_Activity 界面

  • Activity先实现我们刚刚定义的接口,并初始化RecyclerView就可以实现自由拖拽了。(初始化时得把刚刚重写的MyItemTouchHelperCallback 添加到recyclerView对象中)
public class Mistake_Homework_Activity extends BaseActivity implements CallbackItemTouch {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mistake__homework_);
	     //初始化view 
        initView();
	     //设置监听器 
        setListener();
     
    }
	// 初始化方法
  public void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        //设置RecyclerView管理器,这里设置3列
	    gridLayoutManager = new StaggeredGridLayoutManager(3,   StaggeredGridLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(gridLayoutManager);
        //初始化适配器
        mAdapter = new MisTakeHomeWorkAdapter(subList);
          //设置添加或删除item时的动画,这里使用默认动画
          //mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        final ItemTouchHelper.Callback callback = new MyItemTouchHelperCallback(this);// create MyItemTouchHelperCallback
        ItemTouchHelper touchHelper = new ItemTouchHelper(callback); // Create ItemTouchHelper and pass with parameter the MyItemTouchHelperCallback
        touchHelper.attachToRecyclerView(mRecyclerView); // Attach ItemTouchHelper to RecyclerView
        mRecyclerView.setAdapter(mAdapter);
    }


        @Override
    public void itemTouchOnMove(RecyclerView.ViewHolder oldViewHolder, int oldP, int newP, RecyclerView.ViewHolder targetViewHolder) {
      //TODO 此方法在下面实现
    }
    }

5.当然写完上面写代码就能够实现自由拖拽的,但是拖拽后放开后,item的镜像会返回到原地。所以啊,我们还要在拖拽过程中记录当前你把item拖拽到了那个view了,记录下position。当放开时执行我们的逻辑代码,判断是否将这个item放入到目标item中。

在activity中这个回调方法中,记录item镜像移动过程中的 起始position,和最新所在的position

        @Override
    public void itemTouchOnMove(RecyclerView.ViewHolder oldViewHolder, int oldP, int newP, RecyclerView.ViewHolder targetViewHolder) {
           //移动到新的item上方时,给它设置选中颜色
            setChooseColor(newP);
        }
        //记录 position
        this.oldPosition = oldP;
        this.newPosition = newP;
    }
    
    /**
      newP是手指所在的item position
    */
     private void setChooseColor(int newP){
        int count=mRecyclerView.getChildCount();
        for (int i=0;i<count;i++){
            View itemView = mRecyclerView.getChildAt(i);
            int position = (int) itemView.getTag();
            if(newP==position){
                itemView.setBackgroundColor(Color.parseColor("#55cccccc"));
            }else {
                itemView.setBackgroundColor(Color.parseColor("#00ffffff"));
            }
        }
    }

好!既然记录了起始和目标的position了,那我们是不是监听RecyclerView的 setOnTouchListener方法就可以了呢。

mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
  @Override
            public boolean onTouch(View v, MotionEvent event) {
                int type = event.getAction();
                switch (type) {
                    case MotionEvent.ACTION_DOWN:
                    case MotionEvent.ACTION_MOVE:
                        break;
                    case MotionEvent.ACTION_UP:
                        int x = (int) event.getX();
                        int y = (int) event.getY();
                        try {
                            //判断是否移动
                            if (newPosition != -1 && oldPosition != subList.size() - 1) {
                            //根据x y 坐标获取当前手指所在item的position,这个方法在下面贴出代码
                                int position = pointToPosition(x, y);
                                //既然获取了position了,那就好办了,根据position,判断目标position的类型后执行相应的逻辑代码。
                             // TODO ...   
              
                        break;
                        }
                }
             }

//根据坐标,获取所在item 的position值,返回-1则获取失败,可能是在RecyclerView之外,不做处理。

    public int pointToPosition(int x, int y) throws Exception {
        Rect frame = new Rect();
        final int count = mRecyclerView.getChildCount(); //显示的子item 数
        for (int i = count - 1; i >= 0; i--) { // 遍历判断当前xy值所在的position
            final View child = mRecyclerView.getChildAt(i);
            int position = (int) child.getTag();
            if (oldPosition != position) { //忽略移动view的坐标
                if (child.getVisibility() != View.GONE) {
                    child.getHitRect(frame);
                    if (frame.contains(x, y)) {
                        int[] mFirstVisibleItems = null;
                        mFirstVisibleItems = gridLayoutManager.findFirstVisibleItemPositions(mFirstVisibleItems);
                        if (mFirstVisibleItems != null) {
                            int mFirstPosition = mFirstVisibleItems[0];
                            return mFirstPosition + i;
                        }
                    }
                }
            }
        }
        return -1;
    }

好了,将上面几个方法添加到activity中就可能实现自由拖拽啦,其它的也可以自己优化。

猜你喜欢

转载自blog.csdn.net/qq_34256389/article/details/81910121