본문 바로가기
안드로이드 코틀린

[Kotlin][Android] Jetpack Compose 아이템 일괄 삭제하기

by teamnova 2024. 11. 21.
728x90

 

안녕하세요 오늘은 컴포즈로 구현한 아이템 리스트에서 선택된 아이템을 일괄적으로 삭제해보도록 하겠습니다 

 

관련된 이전 포스팅은 아래에서 확인가능 합니다

 

[Kotlin][Android] Jetpack Compose 아이템 텍스트 수정하기

안녕하세요 오늘은 컴포즈로 만든 리스트에서 각 아이템의 텍스트를 수정을 해보겠습니다  아이템마다 수정 버튼이 있습니다 이때 TextField와 "확인" 및 "취소" 버튼이 나타나며, 사용자는 값을

stickode.tistory.com

 

 

목록이 간단할 때에는 큰 필요성을 느끼지 못할 수 있지만 아이템이 많아지면 많아질수록 대량의 아이템을 원하는대로 한번에 처리하는 기능은 꼭 필요한 기능 중 하나입니다 

 

    // 일괄 삭제 버튼
        Row(modifier = Modifier.padding(16.dp)) {
            Button(
                onClick = {
                    // 선택된 아이템들 삭제
                    val iterator = items.iterator()
                    var index = 0
                    while (iterator.hasNext()) {
                        iterator.next()
                        if (selectedItems[index]) {
                            iterator.remove()
                            selectedItems.removeAt(index)
                            isEditing.removeAt(index)
                            index--
                        }
                        index++
                    }
                },
                enabled = selectedItems.contains(true) // 선택된 아이템이 있을 때만 활성화
            ) {
                Text("선택된 아이템 전부 삭제")
            }
        }

 

먼저 삭제버튼을 만들어줍니다 

 

선택된 아이템을 삭제할 때에는 반복문을 통해 item 리스트의 항목들을 순회하면서 선택된 아이템 (selectedItems), 즉 true 로 표시된 아이템들이 삭제됩니다. 

 

 

아래는 전체 코드입니다 

package com.example.kotlin_example

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.kotlin_example.ui.theme.Kotlin_exampleTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Kotlin_exampleTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    ItemList(cnt = 3)
                }
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ItemList(cnt: Int) {
    // 아이템 리스트 초기화
    val items = remember { mutableStateListOf<String>().apply { repeat(cnt) { add("Item ${it + 1}") } } }

    // 체크 박스 상태 리스트
    val selectedItems = remember { mutableStateListOf<Boolean>().apply { repeat(cnt) { add(false) } } }

    // 편집 상태 리스트 (각 아이템이 수정 중인지 여부를 저장)
    val isEditing = remember { mutableStateListOf<Boolean>().apply { repeat(cnt) { add(false) } } }

    // 새로운 아이템 입력 상태
    var newItemText by remember { mutableStateOf("") }

    Column {
        // 새로운 아이템 추가 입력 필드
        Row(modifier = Modifier.padding(16.dp)) {
            TextField(
                value = newItemText,
                onValueChange = { newItemText = it },
                label = { Text("새 아이템 입력") },
                modifier = Modifier.weight(1f)
            )
            Spacer(modifier = Modifier.width(8.dp))
            Button(onClick = {
                if (newItemText.isNotBlank()) {
                    items.add(newItemText)
                    selectedItems.add(false) // 새로운 아이템에 대해 체크박스 상태 추가
                    isEditing.add(false) // 새로운 아이템의 편집 상태 추가
                    newItemText = "" // 입력 필드 초기화
                }
            }) {
                Text("추가")
            }
        }

        // 선택된 아이템 개수를 표시
        Text(
            text = "선택된 아이템: ${selectedItems.count { it }}",
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp),
            color = Color.Blue
        )


        // 일괄 삭제 버튼
        Row(modifier = Modifier.padding(16.dp)) {
            Button(
                onClick = {
                    // 선택된 아이템들 삭제
                    val iterator = items.iterator()
                    var index = 0
                    while (iterator.hasNext()) {
                        iterator.next()
                        if (selectedItems[index]) {
                            iterator.remove()
                            selectedItems.removeAt(index)
                            isEditing.removeAt(index)
                            index--
                        }
                        index++
                    }
                },
                enabled = selectedItems.contains(true) // 선택된 아이템이 있을 때만 활성화
            ) {
                Text("선택된 아이템 일괄 삭제")
            }
        }


        // 체크박스 리스트 표시
        LazyColumn {
            itemsIndexed(items, key = { _, item -> item }) { index, item ->
                val dismissState = rememberSwipeToDismissBoxState(
                    initialValue = SwipeToDismissBoxValue.Settled,
                    confirmValueChange = {
                        if (it != SwipeToDismissBoxValue.Settled) {
                            true
                        } else {
                            false
                        }
                    }
                )

                if (dismissState.currentValue != SwipeToDismissBoxValue.Settled) {
                    LaunchedEffect(dismissState.currentValue) {
                        if (dismissState.currentValue == SwipeToDismissBoxValue.EndToStart ||
                            dismissState.currentValue == SwipeToDismissBoxValue.StartToEnd) {
                            // 삭제할 때 리스트 인덱스가 변경되지 않도록 지연시키는 방식 사용
                            items.removeAt(index)
                            selectedItems.removeAt(index)
                            isEditing.removeAt(index)
                        }
                    }
                }

                SwipeToDismissBox(
                    state = dismissState,
                    backgroundContent = {
                        Box(
                            modifier = Modifier
                                .fillMaxSize()
                                .background(Color.LightGray)
                                .padding(16.dp)
                        )
//                        {
//                            Icon(
//                                imageVector = Icons.Default.Close,
//                                contentDescription = "삭제",
//                                tint = Color.Red
//                            )
//                        }
                    },
                    content = {
                        Row(
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(vertical = 8.dp)
                                .clickable {
                                    selectedItems[index] = !selectedItems[index] // 체크박스 상태 토글
                                }
                                .padding(16.dp),
                            verticalAlignment = Alignment.CenterVertically
                        ) {
                            Checkbox(
                                checked = selectedItems[index],
                                onCheckedChange = { checked -> selectedItems[index] = checked }
                            )
                            if (isEditing[index]) {
                                // 편집 모드일 때 TextField와 확인, 취소 버튼 표시
                                var editText by remember { mutableStateOf(item) }
                                TextField(
                                    value = editText,
                                    onValueChange = { newValue -> editText = newValue },
                                    modifier = Modifier.weight(1f),
                                    singleLine = true
                                )
                                Row {
                                    // 확인 버튼
                                    Button(onClick = {
                                        items[index] = editText // 편집 후 값을 저장
                                        isEditing[index] = false // 편집 모드 종료
                                    }) {
                                        Text("확인")
                                    }
                                    Spacer(modifier = Modifier.width(8.dp))
                                    // 취소 버튼
                                    Button(onClick = {
                                        isEditing[index] = false // 편집 모드 종료
                                    }) {
                                        Text("취소")
                                    }
                                }
                            } else {
                                // 기본 모드일 때 Text와 수정 버튼 표시
                                Text(
                                    text = item,
                                    color = Color.Black,
                                    modifier = Modifier
                                        .weight(1f)
                                        .padding(start = 16.dp)
                                )
                                Spacer(modifier = Modifier.width(8.dp))
                                Button(onClick = {
                                    isEditing[index] = true // 수정 버튼 클릭 시 편집 모드로 전환
                                }) {
                                    Text("수정")
                                }
                            }

                            Spacer(modifier = Modifier.weight(1f)) // X 표시를 오른쪽으로 정렬하기 위한 spacer

                            // 기존 삭제 버튼 유지
                            IconButton(onClick = {
                                items.removeAt(index)
                                selectedItems.removeAt(index)
                                isEditing.removeAt(index)
                            }) {
                                Icon(
                                    imageVector = Icons.Default.Close,
                                    contentDescription = "삭제",
                                    tint = Color.Red
                                )
                            }
                        }
                    }
                )
            }
        }
    }
}


@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    Kotlin_exampleTheme {
        ItemList(cnt = 100)
    }
}

 

 

감사합니다