Android RecyclerView 드래그 앤 드롭
이 튜토리얼에서는 Android 애플리케이션의 RecyclerView를 통해 드래그 앤 드롭 기능을 논의하고 구현합니다. 이전 튜토리얼에서 스 와이프하여 닫기 기능에 대해 이미 논의했습니다.
RecyclerView 드래그 앤 드롭
ItemTouchHelper 유틸리티 클래스를 사용하여 RecyclerView에 드래그 앤 드롭을 추가할 수 있습니다. 다음은 구현해야 하는 ItemTouchHelper.Callback
인터페이스의 중요한 메서드입니다.
isLongPressDragEnabled
- 드래그 앤 드롭을 위해 RecyclerView 행을 길게 누르려면 여기에서 true를 반환합니다.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.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);
}
}
여기서 우리는 RecyclerViewAdapter.java 클래스를 Strings의 ArrayList로 채웠습니다. 드래그 앤 드롭을 시작하기 위해 RecyclerView에 ItemMoveCallback.java 클래스의 인스턴스를 연결했습니다. 각 파일을 살펴보겠습니다. 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);
}
}
여기에서 ItemTouchHelperContract
인터페이스를 정의했습니다. 각 메서드는 ItemTouchHelper.Callback
인터페이스의 구현된 메서드에서 호출됩니다. 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);
}
}

핸들을 사용하여 끌어서 놓기
드래그 앤 드롭에 특정 핸들 보기를 사용하려면 다음 작업을 수행해야 합니다. 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;
}
});

AndroidRecyclerViewDragAndDrop
Github 프로젝트 링크