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

[JAVA][Android] RecyclerView에서 스와이프로 항목 삭제 (Undo 기능 포함)

by teamnova 2025. 2. 10.
728x90

시연 영상

 

 

 

1. 스와이프 삭제 기능이 왜 필요할까요?

1) 사용자 경험(UX) 향상

앱에서 불필요한 항목을 삭제할 때 버튼을 따로 누르기보다 자연스럽게 스와이프하여 삭제하는 방식이 더 직관적입니다.
✔️ 터치 기반 UI에서 스와이프는 손가락 하나로 쉽게 조작할 수 있어 사용자의 피로도를 줄일 수 있음
✔️ 삭제 버튼을 찾을 필요 없이 바로 제거 가능하여 더 빠른 작업 처리 가능

 

2) 화면 공간 절약

✔️ 보통 삭제 버튼이 각 항목마다 따로 배치되면 리스트가 복잡해 보일 수 있음
✔️ 스와이프 동작만으로 삭제 가능하면 UI가 더 깔끔해지고 화면 공간을 더 효율적으로 사용 가능

 

3) 삭제 후 복구 (Undo) 가능

✔️ 실수로 항목을 삭제했을 경우 스낵바(Snackbar)에서 '실행 취소' 버튼을 눌러 복구 가능

 

2. 스와이프 삭제 기능을 어디에 활용하면 좋을까?

1) 메모 & 할 일 목록 (To-Do List)

✔️ 사용자가 완료한 작업을 쉽게 삭제할 수 있음
✔️ "완료" 상태로 변경할 수도 있음 (오른쪽 스와이프 → 완료, 왼쪽 스와이프 → 삭제)

2) 이메일 앱 & 메시지 앱

✔️ 받은 편지함에서 불필요한 이메일을 빠르게 삭제 가능
✔️ 스와이프 방향에 따라 '삭제', '읽음으로 표시', '즐겨찾기 추가' 등 다양한 기능 적용 가능

3) 쇼핑몰 & 장바구니 앱

✔️ 장바구니에서 구매하지 않을 상품을 쉽게 제거 가능
✔️ 찜 목록(위시리스트)에서 상품을 삭제할 때 활용 가능

4) 소셜미디어 & 채팅 앱

✔️ 메시지를 삭제하거나 신고 기능과 연결할 수 있음
✔️ 친구 목록에서 특정 사용자를 삭제할 때 활용 가능

5) 금융 & 가계부 앱

✔️ 사용자가 입력한 지출 내역을 쉽게 삭제 가능
✔️ 특정 지출을 스와이프로 '고정 지출' 또는 '일반 지출'로 변경 가능

3. 스와이프 삭제 기능이 있는 대표적인 앱 사례

✔️ Gmail – 이메일을 스와이프하여 삭제, 보관, 읽음/읽지 않음 설정 가능
✔️ Google Keep – 메모를 스와이프하여 삭제 가능
✔️ 카카오톡 – 채팅방을 스와이프하여 나가기 가능
✔️ 네이버 메모 – 리스트에서 메모를 스와이프하여 삭제 가능

 

 

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;  // RecyclerView 선언
    private ItemAdapter adapter;  // RecyclerView 어댑터 선언
    private List<String> itemList = new ArrayList<>();  // 데이터 목록
    private String deletedItem;  // 삭제된 아이템 저장 변수
    private int deletedPosition; // 삭제된 아이템의 위치 저장 변수

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

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this)); // RecyclerView를 세로 리스트 형태로 설정

        // 더미 데이터 추가 (항목 1 ~ 20)
        for (int i = 1; i <= 20; i++) {
            itemList.add("항목 " + i);
        }

        adapter = new ItemAdapter(itemList);  // 어댑터 생성
        recyclerView.setAdapter(adapter);  // RecyclerView에 어댑터 연결

        // 스와이프 이벤트 추가 (ItemTouchHelper 사용)
        new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
                return false; // 항목 이동 기능은 사용하지 않음
            }

            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
                // 스와이프된 항목의 위치를 저장
                deletedPosition = viewHolder.getAdapterPosition();
                deletedItem = itemList.get(deletedPosition);

                // 리스트에서 항목 삭제
                itemList.remove(deletedPosition);
                adapter.notifyItemRemoved(deletedPosition); // RecyclerView에 삭제 반영

                // Snackbar를 사용하여 삭제 취소(Undo) 기능 제공
                Snackbar.make(recyclerView, "항목 삭제됨", Snackbar.LENGTH_LONG)
                        .setAction("실행 취소", v -> {
                            // 삭제 취소 시 원래 위치에 아이템 복원
                            itemList.add(deletedPosition, deletedItem);
                            adapter.notifyItemInserted(deletedPosition);
                        })
                        .show();
            }
        }).attachToRecyclerView(recyclerView); // RecyclerView에 스와이프 기능 적용
    }

    // RecyclerView 어댑터 (내부 클래스)
    private static class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
        private final List<String> items; // 데이터 리스트

        // 생성자: 리스트를 받아서 저장
        ItemAdapter(List<String> items) {
            this.items = items;
        }

        // ViewHolder 생성 (레이아웃 설정)
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
            return new ViewHolder(view);
        }

        // ViewHolder에 데이터 바인딩 (각 항목의 내용 설정)
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.textView.setText(items.get(position)); // 항목 내용 설정
        }

        // 리스트 개수 반환
        @Override
        public int getItemCount() {
            return items.size();
        }

        // ViewHolder 클래스 (각 항목의 UI 요소 설정)
        static class ViewHolder extends RecyclerView.ViewHolder {
            TextView textView;

            ViewHolder(View itemView) {
                super(itemView);
                textView = itemView.findViewById(android.R.id.text1); // 기본 제공되는 리스트 아이템 텍스트뷰 사용
            }
        }
    }
}

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>