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中就可能实现自由拖拽啦,其它的也可以自己优化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
实现两个RecyclerView之间的item互相拖拽可以通过以下步骤进行: 1. 首先,在布局文件中分别添加两个RecyclerView控件。给它们分别设置不同的ID,方便后续代码操作。 2. 在代码中分别找到两个RecyclerView实例,并为它们设置LayoutManager和Adapter。确保两个RecyclerView显示的数据不同。 3. 为每个RecyclerView的Item添加拖拽功能,可以使用ItemTouchHelper类来实现。创建一个ItemTouchHelper实例,并将其附加到两个RecyclerView上。 4. 实现ItemTouchHelper.Callback类,重写以下几个方法: - getMovementFlags:指定拖拽和滑动的方向,可以使用ItemTouchHelper.UP、ItemTouchHelper.DOWN、ItemTouchHelper.LEFT、ItemTouchHelper.RIGHT等常量。 - onMove:处理拖拽事件,通过交换两个Item的位置实现互相拖拽。 - onSwiped:处理滑动事件,可以在这个方法中实现删除Item的操作。 5. 在RecyclerView的Adapter中对Item的触摸事件进行监听,当用户按下item时,调用startDrag方法来开始拖拽。 6. 当拖拽结束时,将交换过位置的数据更新到对应的数据源中,并刷新RecyclerView。 通过以上步骤,就可以实现两个RecyclerView之间的item互相拖拽了。可以在同一个Activity或Fragment中同时显示这两个RecyclerView,或者在不同的页面中分别显示这两个RecyclerView。这样用户就可以通过拖拽的方式,将一个RecyclerView的item拖放到另一个RecyclerView中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值