You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Compose中实现LazyVerticalGrid项长按选中及批量删除

实现LazyVerticalGrid图片项的长按选中与批量删除功能

1. 先在ViewModel中维护选中状态

选中状态需要跨组件共享,所以把核心状态和操作逻辑放在ViewModel里:

class PhotoViewModel : ViewModel() {
    // 存储选中的照片,用mutableStateSet自动触发UI重组
    val selectedPhotos = mutableStateSetOf<Photo>()
    
    // 派生状态,自动判断是否处于选择模式
    val isSelectionMode = derivedStateOf { selectedPhotos.isNotEmpty() }

    // 切换单张照片的选中状态
    fun togglePhotoSelection(photo: Photo) {
        if (selectedPhotos.contains(photo)) {
            selectedPhotos.remove(photo)
        } else {
            selectedPhotos.add(photo)
        }
    }

    // 全选/取消全选逻辑
    fun toggleSelectAll(photos: List<Photo>) {
        if (selectedPhotos.size == photos.size) {
            selectedPhotos.clear()
        } else {
            selectedPhotos.addAll(photos)
        }
    }

    // 删除选中照片的逻辑(这里需要你补充实际的删除操作,比如数据库删除)
    fun deleteSelectedPhotos() {
        // 执行删除操作...
        selectedPhotos.clear()
    }
}

2. 修改Photo组件,支持选中状态和长按事件

给Photo组件添加选中状态参数、切换回调,同时区分普通/选择模式的点击行为:

@Composable
fun Photo(
    photo: Photo,
    navController: NavController,
    isSelected: Boolean,
    onToggleSelected: () -> Unit,
    isSelectionMode: Boolean
) {
    val painter = rememberAsyncImagePainter(model = photo.uri)
    Box(
        modifier = Modifier
            .width(150.dp)
            .height(150.dp)
            .clickable {
                if (isSelectionMode) {
                    // 选择模式下点击切换选中状态
                    onToggleSelected()
                } else {
                    // 普通模式下跳转到详情页
                    val args = URLEncoder.encode(photo.uri, StandardCharsets.UTF_8.toString())
                    navController.navigate(Destinations.DetailScreen.withArgs(args))
                }
            }
            .pointerInput(Unit) {
                detectTapGestures(
                    onLongPress = {
                        // 长按触发选中,进入选择模式
                        onToggleSelected()
                    }
                )
            }
    ) {
        Image(
            painter = painter,
            contentDescription = null,
            contentScale = ContentScale.Fit,
            modifier = Modifier.matchParentSize()
        )

        // 选中状态的遮罩和标记
        if (isSelected) {
            Box(
                modifier = Modifier
                    .matchParentSize()
                    .background(Color.Black.copy(alpha = 0.3f))
            )
            Icon(
                imageVector = Icons.Filled.CheckCircle,
                contentDescription = "已选中",
                tint = Color.White,
                modifier = Modifier
                    .align(Alignment.TopEnd)
                    .padding(4.dp)
                    .size(24.dp)
            )
        }
    }
}

3. 改造MainScreen,添加选择模式控制和操作按钮

引入ViewModel,根据选择模式切换UI,添加全选、删除按钮:

@Composable
fun MainScreen(navController: NavController, viewModel: PhotoViewModel = viewModel()) {
    val photoList by viewModel.allPhotos.collectAsState(initial = emptyList())
    val selectedPhotos = viewModel.selectedPhotos
    val isSelectionMode = viewModel.isSelectionMode.value

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color(android.graphics.Color.parseColor("#50E1E6")))
    ) {
        if (photoList.isEmpty()) {
            TextContent()
        } else {
            LazyVerticalGrid(
                columns = GridCells.Fixed(3),
                contentPadding = PaddingValues(5.dp)
            ) {
                items(photoList) { photo ->
                    Column {
                        Photo(
                            photo = photo,
                            navController = navController,
                            isSelected = selectedPhotos.contains(photo),
                            onToggleSelected = { viewModel.togglePhotoSelection(photo) },
                            isSelectionMode = isSelectionMode
                        )
                        Divider(color = Color.Transparent, thickness = 5.dp)
                    }
                }
            }
        }

        // 选择模式下显示全选和删除按钮
        if (isSelectionMode) {
            Row(
                modifier = Modifier
                    .align(Alignment.TopCenter)
                    .fillMaxWidth()
                    .padding(horizontal = 16.dp, vertical = 8.dp),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                TextButton(
                    onClick = { viewModel.toggleSelectAll(photoList) }
                ) {
                    Text(
                        text = if (selectedPhotos.size == photoList.size) "取消全选" else "全选",
                        color = Color.White
                    )
                }
                Button(
                    onClick = { viewModel.deleteSelectedPhotos() },
                    colors = ButtonDefaults.buttonColors(Color.Red)
                ) {
                    Text(text = "删除(${selectedPhotos.size})", color = Color.White)
                }
            }
        }

        // 普通模式下显示添加图片按钮
        if (!isSelectionMode) {
            Button(
                onClick = {
                    navController.navigate(Destinations.CameraScreen.routes)
                    startCamera()
                },
                modifier = Modifier.align(Alignment.BottomEnd)
            ) {
                Text(text = "添加图片")
            }
        }
    }
}

关键说明

  • 用mutableStateSetOf存储选中项,集合变化时会自动触发UI重组
  • 通过detectTapGestures区分单击和长按事件,长按直接进入选择模式
  • 选择模式下,点击图片切换选中状态;普通模式下保持原有的跳转逻辑
  • 全选按钮会根据当前选中数量自动切换文字(全选/取消全选)

内容的提问来源于stack exchange,提问作者Den

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 23:54:56