본문 바로가기
안드로이드 자바

[Android][Java] Recycleview에 ItemTouchHelper로 스와이프 및 드래그 앤 드롭 동작 구현

by teamnova 2022. 10. 31.
728x90

안녕하세요. 오늘은 RecyclerView에 스와이프 해제 및 드래그 앤 드롭 지원을 추가하는 유틸리티 클래스인 ItemTouchHelper를 사용해보겠습니다.

구현 순서는 다음과 같습니다.

1. ItemTouchHelper.callback 을 상속받는 클래스를 생성합니다.  클래스 이름은 CustomItemTouchHelperCallback입니다

2. CustomItemTouchHelperCallback 클래스 내에서 인터페이스(OnItemTouchListener)를 선언합니다.

3. CustomItemTouchHelperCallback 클래스의 생성자 파라미터로 인터페이스 OnItemTouchListener를 받습니다

4. CustomItemTouchHelperCallback 내에서 getMovementFlags(),onMove(),onSwipe() 메서드내에서 인터페이스를 리턴해줍니다.

5. MainActivity에서 CustomItemTouchHelperCallback내에서 선언한 interface를 implement 하고, 해당 메서드를 재정의합니다.

6. ItemTouchHelper 인스턴스를 생성합니다. 이 때, 파라미터로 콜백을 정의한 클래스인 CustomItemTouchHelperCallback 인스턴스를 넣어줍니다. 

7.itemTouchHelper.attachToRecyclerView(recyclerView); CustomItemTouchHelperCallback 클래스의 콜백메서드들이 동작하도록 itemTouchHelper 객체에 리사이클러뷰를 붙혀줍니다.

 

이렇게 하면 스와이프, 이동 이벤트가 동작하게 됩니다. 

 

ItemTouchHelper itemTouchHelper=new ItemTouchHelper(new CustomItemTouchHelperCallback(this));
itemTouchHelper.attachToRecyclerView(recyclerView);

ItemTouchHelper 

전체 코드입니다. 

CustomItemTouchHelperCallback.java

import android.util.Log;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

public class CustomItemTouchHelperCallback extends ItemTouchHelper.Callback{
    private final String TAG=this.getClass().getSimpleName();
    private OnItemTouchListener listener;
    public CustomItemTouchHelperCallback(OnItemTouchListener listener) {
        this.listener = listener;
    }

    /**
     * Should return a composite flag which defines the enabled move directions in each state (idle, swiping, dragging).
     * Instead of composing this flag manually, you can use makeMovementFlags(int, int) or makeFlag(int, int).
     * This flag is composed of 3 sets of 8 bits, where first 8 bits are for IDLE state, next 8 bits are for SWIPE state and third 8 bits are for DRAG state. Each 8 bit sections can be constructed by simply OR'ing direction flags defined in ItemTouchHelper.
     * For example, if you want it to allow swiping LEFT and RIGHT but only allow starting to swipe by swiping RIGHT, you can return:
     *                 makeFlag(ACTION_STATE_IDLE, RIGHT) | makeFlag(ACTION_STATE_SWIPE, LEFT | RIGHT);
     *
     * This means, allow right movement while IDLE and allow right and left movement while swiping.
     * Params:
     * recyclerView – The RecyclerView to which ItemTouchHelper is attached.
     * viewHolder – The ViewHolder for which the movement information is necessary.
     * Returns:
     * flags specifying which movements are allowed on this ViewHolder.
     * See Also:
     * makeMovementFlags(int, int), makeFlag(int, int)*/
    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        Log.d(TAG, "getMovementFlags: ");
        return makeMovementFlags(ItemTouchHelper.UP|ItemTouchHelper.DOWN,ItemTouchHelper.START|ItemTouchHelper.END);
    }
    /**
     * 아이템 이동 메서드
     * */
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        return listener.moveItem(viewHolder.getAdapterPosition(),target.getAdapterPosition());
    }
    /**
     * 스와이프 == 삭제
     * */
    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        Log.d(TAG, "onSwiped: ");
        listener.removeItem(viewHolder.getAdapterPosition());
    }
    public interface OnItemTouchListener{
        boolean moveItem(int fromPosition,int toPosition);
        void removeItem(int position);
    }
}

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements CustomItemTouchHelperCallback.OnItemTouchListener {
    private final String TAG=this.getClass().getSimpleName();
    private ArrayList<Data> mArrayList;
    private RecyclerView recyclerView;
    private MyAdapter mAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView=findViewById(R.id.rv);
        mArrayList=new ArrayList();
        getData();
        setRecyclerView(mArrayList);
    }
    /**
     * 리사이클러뷰 세팅
     * */
    private void setRecyclerView(ArrayList mArrayList) {
        mAdapter=new MyAdapter(mArrayList);
        recyclerView.setLayoutManager(new LinearLayoutManager(this,RecyclerView.VERTICAL,false));
        recyclerView.setAdapter(mAdapter);
        ItemTouchHelper itemTouchHelper=new ItemTouchHelper(new CustomItemTouchHelperCallback(this));
        /**
         * Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already attached to a RecyclerView, it will first detach from the previous one. You can call this method with null to detach it from the current RecyclerView.
         * Params:
         * recyclerView – The RecyclerView instance to which you want to add this helper or null if you want to remove ItemTouchHelper from the current RecyclerView.
         * itemTouchHelper 객체에 리사이클러뷰를 붙혀줌으로써, CustomItemTouchHelperCallback 클래스의 콜백메서드들이 동작한다.
         * */
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }
    /**
     * 데이터 생성
     * */
    private void getData() {
        for(int i=0;i<10;i++){
            Data data=new Data("제목"+i,"내용"+i,false);
            mArrayList.add(data);
        }
    }

    /** 재정의 메서드
     * */
    @Override
    public boolean moveItem(int fromPosition, int toPosition) {
        Log.d(TAG, "moveItem: ");
        Data data=mArrayList.get(fromPosition);
        mArrayList.remove(fromPosition);
        mArrayList.add(toPosition,data);
        mAdapter.notifyItemMoved(fromPosition,toPosition);
        return false;
    }

    /** 재정의 메서드
     * */
    @Override
    public void removeItem(int position) {
        Log.d(TAG, "removeItem: ");
        mArrayList.remove(position);
        mAdapter.notifyDataSetChanged();
    }
}

MyAdapter.java

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private final String TAG=this.getClass().getSimpleName();
    private ArrayList<Data> mList;

    public MyAdapter(ArrayList<Data> mList) {
        this.mList = mList;
    }

    @NonNull
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
        ViewHolder viewHolder=new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
        holder.tv_title.setText(mList.get(position).getTitle());
        holder.tv_content.setText(mList.get(position).getContent());
        if(mList.get(position).isChecked()){
            holder.checkBox.setChecked(true);
        }else {
            holder.checkBox.setChecked(false);
        }
    }

    @Override
    public int getItemCount() {
        return (null!=mList?mList.size():0);
    }

    public class ViewHolder extends RecyclerView.ViewHolder{
        private TextView tv_title;
        private TextView tv_content;
        private CheckBox checkBox;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            this.tv_title=itemView.findViewById(R.id.tv_title);
            this.tv_content=itemView.findViewById(R.id.tv_content);
            this.checkBox=itemView.findViewById(R.id.checkbox);
        }
    }
}

 

https://developer.android.com/reference/androidx/recyclerview/widget/ItemTouchHelper

 

 

ItemTouchHelper  |  Android Developers

androidx.car.app.managers

developer.android.com