웹사이트 검색

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 프로젝트 링크