Android RecyclerView拖放
在本教程中,我们将在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; } });
您可以在本教程末尾的下载链接中找到更新的代码。