In this tutorial, we’ll be discussing and implementing the Drag and Drop functionality over our RecyclerView in an Android Application. We’ve already discussed Swipe to Dismiss feature in our previous tutorial.
在本教程中,我们将在Android应用程序中的RecyclerView上讨论和实现拖放功能。 在上一教程中,我们已经讨论了“滑动以关闭”功能。
RecyclerView拖放 (RecyclerView Drag and Drop)
Drag and Drop can be added in a RecyclerView using the ItemTouchHelper utility class.
可以使用ItemTouchHelper实用程序类在RecyclerView中添加拖放。
Following are the important methods in the ItemTouchHelper.Callback
interface which needs to be implemented:
以下是ItemTouchHelper.Callback
接口中需要实现的重要方法:
isLongPressDragEnabled
– return true here to enable long press on the RecyclerView rows for drag and drop.isLongPressDragEnabled
–在此处返回true,以使长按RecyclerView行以进行拖放。isItemViewSwipeEnabled
– This is used to enable or disable swipes. In this tutorial, we’ll disable this.isItemViewSwipeEnabled
–用于启用或禁用滑动。 在本教程中,我们将禁用它。getMovementFlags
– Here we pass the flags for the directions of drag and swipe. Since swipe is disable we pass 0 for it.getMovementFlags
–在这里,我们传递用于拖动和滑动方向的标志。 由于禁用了滑动,因此我们将其传递为0。onMove
– Here we set the code for the drag and drop.
onSwipe – Here we implement the code for swiping. We’ll keep this empty in the current tutorial.onMove
–在这里,我们为拖放设置代码。
onSwipe –在这里,我们实现了刷卡代码。 在本教程中,我们将其保留为空。onSelectedChanged
– Based on the current state of the RecyclerView and whether it’s pressed or swiped, this method gets triggered. Here we can customize the RecyclerView row. For example, changing the background color.onSelectedChanged
–根据RecyclerView的当前状态以及是否按下或滑动,将触发此方法。 在这里,我们可以自定义RecyclerView行。 例如,更改背景颜色。clearView
– This method gets triggered when the user interaction stops with the RecyclerView row.clearView
–当用户与RecyclerView行停止交互时,将触发此方法。
Let’s start building our android application with the drag and drop feature on the RecyclerView.
让我们开始使用RecyclerView上的拖放功能来构建我们的android应用程序。
项目结构 (Project Structure)
码 (Code)
The code for the activity_main.xml layout which contains a RecyclerView only is given below:
下面给出了仅包含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>
The code for the MainActivity.java is given below:
MainActivity.java的代码如下:
package com.journaldev.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);
}
}
In this, we’ve populated a RecyclerViewAdapter.java class with an ArrayList of Strings.
在此,我们用字符串的ArrayList填充了RecyclerViewAdapter.java类。
We’ve attached an instance of the ItemMoveCallback.java class on the RecyclerView to start drag and drop.
我们已经在RecyclerView上附加了ItemMoveCallback.java类的实例,以开始拖放操作。
Let’s look at each of these files.
让我们看一下每个文件。
The code for the ItemMoveCallback.java class is given below:
下面给出了ItemMoveCallback.java类的代码:
package com.journaldev.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);
}
}
Here, we’ve defined an interface ItemTouchHelperContract
. Each of its methods get called from the implemented methods of the ItemTouchHelper.Callback
interface.
在这里,我们定义了一个接口ItemTouchHelperContract
。 它的每个方法都可以从ItemTouchHelper.Callback
接口的已实现方法中ItemTouchHelper.Callback
。
The code for the RecyclerViewAdapter.java class is given below:
下面给出了RecyclerViewAdapter.java类的代码:
package com.journaldev.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);
}
}
onRowMoved
defined in the Contract interface earlier gets called when the drag and drop is done.
Here we swap the positions of the two rows present in the ArrayList and call notifyItemMoved to refresh the adapter.
完成拖放操作后,将更早调用Contract接口中定义的onRowMoved
。
在这里,我们交换ArrayList中存在的两行的位置,并调用notifyItemMoved刷新适配器。
The output of the above application in action is given below:
上面应用程序的输出如下:
Up until now, we’ve done the drag and drop by pressing anywhere in the RecyclerView rows.
Next, we’ll see how to do the same by pressing only a particular view inside the RecyclerView row.
到目前为止,我们已经通过在RecyclerView行中的任意位置进行了拖放。
接下来,我们将看到如何通过仅按RecyclerView行内的特定视图来执行相同的操作。
使用手柄拖放 (Drag And Drop using Handles)
In order to use a specific handle view to drag and drop we need to do the following things:
为了使用特定的手柄视图进行拖放,我们需要执行以下操作:
Set isLongPressDragEnabled
to false to disable the default drag and drop.
将isLongPressDragEnabled
设置为false可禁用默认的拖放。
Create an interface like:
创建一个界面,如:
public interface StartDragListener {
void requestDrag(RecyclerView.ViewHolder viewHolder);
}
Implement it on the MainActivity and pass it to the Adapter.
在MainActivity上实现它,并将其传递给适配器。
@Override
public void requestDrag(RecyclerView.ViewHolder viewHolder) {
touchHelper.startDrag(viewHolder);
}
mAdapter = new RecyclerViewAdapter(stringArrayList,this);
Inside the RecyclerViewAdapter.java do the following:
在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;
}
});
You can find the updated code in the download link at the end of this tutorial.
您可以在本教程末尾的下载链接中找到更新的代码。
The output of the application with the updated code is given below:
带有更新代码的应用程序输出如下:
This brings an end to this tutorial. The complete source code of the project is given below:
本教程到此结束。 该项目的完整源代码如下:
翻译自: https://www.journaldev.com/23208/android-recyclerview-drag-and-drop