웹사이트 검색

Android RecyclerView 스 와이프하여 삭제 및 실행 취소


이 튜토리얼에서는 Android 애플리케이션의 RecyclerView에서 스와이프하여 삭제 기능에 대해 논의하고 구현합니다.

Android 스 와이프하여 삭제

스 와이프하여 삭제 기능은 일반적으로 RecyclerView에서 행을 삭제하는 데 사용됩니다. 스와이프하여 삭제 기능을 구현하려면 ItemTouchHelper 유틸리티 클래스를 사용해야 합니다.

ItemTouchHelper.Callback

ItemTouchHelper 클래스를 사용하기 위해서는 ItemTouchHelper.Callback을 구현해야 합니다. ItemTouchHelper.Callback 클래스는 주로 드래그 앤 드롭 및 스와이프하여 동작을 삭제하는 데 사용됩니다. 이 튜토리얼에서는 스 와이프하여 삭제만 할 것입니다. Android 프레임워크는 SimpleCallback인 ItemTouchHelper.Callback의 기본 구현을 제공합니다. 스와이프하여 삭제 기능의 자체 구현을 만들 것입니다. 다음은 클래스에서 재정의해야 하는 주요 메서드입니다. getMovementFlags - 여기에서 스와이프 방향을 설정합니다. 정적 메서드 makeMovementFlags에서 방향 플래그를 반환합니다. onMove - 드래그 앤 드롭에 사용됩니다. 필요하지 않은 경우 여기에 false를 반환합니다. onSwiped - 스와이프 동작이 감지되면 트리거됩니다. 전체 스 와이프는 화면의 전체 너비로 이동합니다. 부분 스와이프를 스와이프로 간주하도록 설정하려면 다음 메서드를 재정의해야 합니다. getSwipeThreshold - 여기에서 float 값을 반환합니다. 예 0.5f는 RecyclerView 행에서 50% 스와이프가 스와이프로 간주됨을 의미합니다. onChildDraw - 여기에서 스와이프가 발생하고 있음을 보여주는 사용자 정의 보기를 생성합니다.

ItemTouchHelper.Callback은 행을 스 와이프하는 데 사용됩니다. 그것들 자체를 삭제하지는 않습니다. RecyclerView 어댑터를 사용하여 직접 삭제해야 합니다.

충분한 이야기. 코딩합시다. 다음 섹션에서는 Swipe to Dismiss 기능이 포함된 RecyclerView를 사용하여 Android 애플리케이션을 만들 것입니다. 취소 옵션이 있는 Snackbar를 제공합니다.

프로젝트 구조

implementation 'com.android.support:design:28.0.0-rc01'

암호

activity_main.xml 레이아웃의 코드는 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:id="@+id/coordinatorLayout"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <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" />


    </RelativeLayout>

</android.support.design.widget.CoordinatorLayout>

ItemTouchHelper.Callback 클래스를 확장하는 SwipeToDeleteCallback.java 클래스의 코드는 다음과 같습니다.

package com.journaldev.androidrecyclerviewswipetodelete;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.View;

abstract public class SwipeToDeleteCallback extends ItemTouchHelper.Callback {

    Context mContext;
    private Paint mClearPaint;
    private ColorDrawable mBackground;
    private int backgroundColor;
    private Drawable deleteDrawable;
    private int intrinsicWidth;
    private int intrinsicHeight;


    SwipeToDeleteCallback(Context context) {
        mContext = context;
        mBackground = new ColorDrawable();
        backgroundColor = Color.parseColor("#b80f0a");
        mClearPaint = new Paint();
        mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        deleteDrawable = ContextCompat.getDrawable(mContext, R.drawable.ic_delete);
        intrinsicWidth = deleteDrawable.getIntrinsicWidth();
        intrinsicHeight = deleteDrawable.getIntrinsicHeight();
        

    }


    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        return makeMovementFlags(0, ItemTouchHelper.LEFT);
    }

    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder viewHolder1) {
        return false;
    }

    @Override
    public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);

        View itemView = viewHolder.itemView;
        int itemHeight = itemView.getHeight();

        boolean isCancelled = dX == 0 && !isCurrentlyActive;

        if (isCancelled) {
            clearCanvas(c, itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom());
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            return;
        }

        mBackground.setColor(backgroundColor);
        mBackground.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
        mBackground.draw(c);

        int deleteIconTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2;
        int deleteIconMargin = (itemHeight - intrinsicHeight) / 2;
        int deleteIconLeft = itemView.getRight() - deleteIconMargin - intrinsicWidth;
        int deleteIconRight = itemView.getRight() - deleteIconMargin;
        int deleteIconBottom = deleteIconTop + intrinsicHeight;


        deleteDrawable.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom);
        deleteDrawable.draw(c);

        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);


    }

    private void clearCanvas(Canvas c, Float left, Float top, Float right, Float bottom) {
        c.drawRect(left, top, right, bottom, mClearPaint);

    }

    @Override
    public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
        return 0.7f;
    }
}

onSwipe 메소드를 구현하지 않았기 때문에 클래스는 추상적입니다. MainActivity.java 클래스에서 그렇게 할 것입니다. onChildDraw 메서드 내에서 isCancelled 부울을 사용하여 스와이프가 완료되었는지 여부를 확인합니다. 이를 바탕으로 삭제 아이콘이 있는 보기를 만듭니다. 스와이프 임계값을 0.7로 설정했습니다. 즉, 행이 70% 미만으로 스와이프되면 onSwipe 메서드가 트리거되지 않습니다. MainActivity.java 클래스의 코드는 다음과 같습니다.

package com.journaldev.androidrecyclerviewswipetodelete;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.View;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {


    RecyclerView recyclerView;
    RecyclerViewAdapter mAdapter;
    ArrayList<String> stringArrayList = new ArrayList<>();
    CoordinatorLayout coordinatorLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);
        coordinatorLayout = findViewById(R.id.coordinatorLayout);

        populateRecyclerView();
        enableSwipeToDeleteAndUndo();


    }

    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);
        recyclerView.setAdapter(mAdapter);


    }

    private void enableSwipeToDeleteAndUndo() {
        SwipeToDeleteCallback swipeToDeleteCallback = new SwipeToDeleteCallback(this) {
            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {

                
                final int position = viewHolder.getAdapterPosition();
                final String item = mAdapter.getData().get(position);

                mAdapter.removeItem(position);


                Snackbar snackbar = Snackbar
                        .make(coordinatorLayout, "Item was removed from the list.", Snackbar.LENGTH_LONG);
                snackbar.setAction("UNDO", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        
                        mAdapter.restoreItem(item, position);
                        recyclerView.scrollToPosition(position);
                    }
                });

                snackbar.setActionTextColor(Color.YELLOW);
                snackbar.show();

            }
        };

        ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeToDeleteCallback);
        itemTouchhelper.attachToRecyclerView(recyclerView);
    }


}

ItemTouchHelper를 RecyclerView에 설정하기 위해 attachToRecyclerView 메서드가 사용됩니다. Snackbar 작업을 클릭하면 restoreItem 메서드를 사용하여 RecyclerView에서 항목을 복원합니다. restoreItem 메서드는 RecyclerViewAdapter 클래스에서 정의됩니다. scrollToPosition은 RecyclerView를 지정된 위치로 스크롤합니다. RecyclerView 상단에 항목을 삽입할 때 주로 사용합니다. cardview_row.xml의 코드는 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:card_view="https://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="64dp"
    android:layout_margin="8dp"
    card_view:cardCornerRadius="0dp"
    card_view:cardElevation="2dp">


    <RelativeLayout
        android:id="@+id/relativeLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="8dp"
        android:paddingLeft="8dp"
        android:paddingRight="8dp">


        <TextView
            android:id="@+id/txtTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:text="Item 1"
            android:textAppearance="@style/TextAppearance.Compat.Notification.Title" />
    </RelativeLayout>

</android.support.v7.widget.CardView>

RecyclerViewAdapter.java 클래스의 코드는 다음과 같습니다.

package com.journaldev.androidrecyclerviewswipetodelete;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {

    private ArrayList<String> data;

    public class MyViewHolder extends RecyclerView.ViewHolder {

        private TextView mTitle;
        RelativeLayout relativeLayout;

        public MyViewHolder(View itemView) {
            super(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();
    }


    public void removeItem(int position) {
        data.remove(position);
        notifyItemRemoved(position);
    }

    public void restoreItem(String item, int position) {
        data.add(position, item);
        notifyItemInserted(position);
    }

    public ArrayList<String> getData() {
        return data;
    }
}


AndroidRecyclerViewSwipeToDelete

Github 프로젝트 링크