如何在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
相关产品推荐
相关产品推荐

