Android RecyclerView拖放

时间:2020-02-23 14:29:11  来源:igfitidea点击:

在本教程中,我们将在Android应用程序中通过RecyclerView讨论和实现拖放功能。
我们已经在上一教程中讨论了"滑动以关闭"功能。

RecyclerView拖放

可以使用ItemTouchHelper实用工具类在RecyclerView中添加拖放。

以下是ItemTouchHelper.Callback接口中需要实现的重要方法:

  • isLongPressDragEnabled-在此处返回true,以使长按RecyclerView行以进行拖放。

  • isItemViewSwipeEnabled-用于启用或者禁用滑动。
    在本教程中,我们将禁用它。

  • getMovementFlags–其中我们传递用于拖动和滑动方向的标志。
    由于禁用了滑动,因此我们将其传递为0。

  • onMove –其中我们为拖放设置代码。

onSwipe –其中我们实现了刷卡代码。
在本教程中,我们将其保留为空。

  • " onSelectedChanged" –根据RecyclerView的当前状态以及是否按下或者滑动,都会触发此方法。
    其中我们可以自定义RecyclerView行。
    例如,更改背景颜色。

  • clearView-当用户与RecyclerView行停止交互时,将触发此方法。

让我们开始使用RecyclerView上的拖放功能来构建我们的android应用程序。

代码

下面给出了仅包含RecyclerView的activity_main.xml布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity">

  <android.support.v7.widget.RecyclerView
      android:id="@+id/recyclerView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:orientation="vertical"
      app:layoutManager="android.support.v7.widget.LinearLayoutManager" 

</LinearLayout>

MainActivity.java的代码如下:

package com.theitroad.androidrecyclerviewdraganddrop;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

  RecyclerView recyclerView;
  RecyclerViewAdapter mAdapter;
  ArrayList<String> stringArrayList = new ArrayList<>();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      recyclerView = findViewById(R.id.recyclerView);

      populateRecyclerView();
  }

  private void populateRecyclerView() {
      stringArrayList.add("Item 1");
      stringArrayList.add("Item 2");
      stringArrayList.add("Item 3");
      stringArrayList.add("Item 4");
      stringArrayList.add("Item 5");
      stringArrayList.add("Item 6");
      stringArrayList.add("Item 7");
      stringArrayList.add("Item 8");
      stringArrayList.add("Item 9");
      stringArrayList.add("Item 10");

      mAdapter = new RecyclerViewAdapter(stringArrayList);

      ItemTouchHelper.Callback callback =
              new ItemMoveCallback(mAdapter);
      ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
      touchHelper.attachToRecyclerView(recyclerView);

      recyclerView.setAdapter(mAdapter);
  }

}

在此,我们用字符串的ArrayList填充了RecyclerViewAdapter.java类。

我们已经在RecyclerView上附加了ItemMoveCallback.java类的实例,以开始拖放操作。

让我们看一下每个文件。

下面给出了ItemMoveCallback.java类的代码:

package com.theitroad.androidrecyclerviewdraganddrop;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

public class ItemMoveCallback extends ItemTouchHelper.Callback {

  private final ItemTouchHelperContract mAdapter;

  public ItemMoveCallback(ItemTouchHelperContract adapter) {
      mAdapter = adapter;
  }

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

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

  @Override
  public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {

  }

  @Override
  public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
      int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
      return makeMovementFlags(dragFlags, 0);
  }

  @Override
  public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                        RecyclerView.ViewHolder target) {
      mAdapter.onRowMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
      return true;
  }

  @Override
  public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
                                int actionState) {

      if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
          if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
              RecyclerViewAdapter.MyViewHolder myViewHolder=
                      (RecyclerViewAdapter.MyViewHolder) viewHolder;
              mAdapter.onRowSelected(myViewHolder);
          }

      }

      super.onSelectedChanged(viewHolder, actionState);
  }
  @Override
  public void clearView(RecyclerView recyclerView,
                        RecyclerView.ViewHolder viewHolder) {
      super.clearView(recyclerView, viewHolder);

      if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
          RecyclerViewAdapter.MyViewHolder myViewHolder=
                  (RecyclerViewAdapter.MyViewHolder) viewHolder;
          mAdapter.onRowClear(myViewHolder);
      }
  }

  public interface ItemTouchHelperContract {

      void onRowMoved(int fromPosition, int toPosition);
      void onRowSelected(RecyclerViewAdapter.MyViewHolder myViewHolder);
      void onRowClear(RecyclerViewAdapter.MyViewHolder myViewHolder);

  }

}

其中我们定义了一个接口ItemTouchHelperContract。
它的每个方法都可以从ItemTouchHelper.Callback接口的已实现方法中调用。

下面给出了RecyclerViewAdapter.java类的代码:

package com.theitroad.androidrecyclerviewdraganddrop;

import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> implements ItemMoveCallback.ItemTouchHelperContract {

  private ArrayList<String> data;

  public class MyViewHolder extends RecyclerView.ViewHolder {

      private TextView mTitle;
      View rowView;

      public MyViewHolder(View itemView) {
          super(itemView);

          rowView = itemView;
          mTitle = itemView.findViewById(R.id.txtTitle);
      }
  }

  public RecyclerViewAdapter(ArrayList<String> data) {
      this.data = data;
  }

  @Override
  public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_row, parent, false);
      return new MyViewHolder(itemView);
  }

  @Override
  public void onBindViewHolder(MyViewHolder holder, int position) {
      holder.mTitle.setText(data.get(position));
  }

  @Override
  public int getItemCount() {
      return data.size();
  }

  @Override
  public void onRowMoved(int fromPosition, int toPosition) {
      if (fromPosition < toPosition) {
          for (int i = fromPosition; i < toPosition; i++) {
              Collections.swap(data, i, i + 1);
          }
      } else {
          for (int i = fromPosition; i > toPosition; i--) {
              Collections.swap(data, i, i - 1);
          }
      }
      notifyItemMoved(fromPosition, toPosition);
  }

  @Override
  public void onRowSelected(MyViewHolder myViewHolder) {
      myViewHolder.rowView.setBackgroundColor(Color.GRAY);

  }

  @Override
  public void onRowClear(MyViewHolder myViewHolder) {
      myViewHolder.rowView.setBackgroundColor(Color.WHITE);

  }
}

完成拖放操作后,将调用先前在Contract接口中定义的onRowMoved。
其中我们交换ArrayList中存在的两行的位置,并调用notifyItemMoved刷新适配器。

上面应用程序的输出如下:

到目前为止,我们已经通过在RecyclerView行中按任意位置来完成拖放操作。
接下来,我们将看到如何通过仅按RecyclerView行内的特定视图来执行相同的操作。

使用手柄拖放

为了使用特定的手柄视图进行拖放,我们需要做以下事情:

isLongPressDragEnabled设置为false可禁用默认的拖放功能。

创建一个如下界面:

public interface StartDragListener {
  void requestDrag(RecyclerView.ViewHolder viewHolder);
}

在MainActivity上实现它,并将其传递给适配器。

@Override
  public void requestDrag(RecyclerView.ViewHolder viewHolder) {
      touchHelper.startDrag(viewHolder);
  }
mAdapter = new RecyclerViewAdapter(stringArrayList,this);

在RecyclerViewAdapter.java中,执行以下操作:

holder.imageView.setOnTouchListener(new View.OnTouchListener() {
          @Override
          public boolean onTouch(View v, MotionEvent event) {
              if (event.getAction() ==
                      MotionEvent.ACTION_DOWN) {
                  mStartDragListener.requestDrag(holder);
              }
              return false;
          }
      });

您可以在本教程末尾的下载链接中找到更新的代码。