我想让用户添加图像到每个项目(卡)在LazyColumn.但似乎图像在重新构图时被删除了.我怎么才能解决这个问题呢?

@Composable
fun PhotoUpload(
) {
    val imageUri = remember {
        mutableStateOf<Uri?>(null)
    }
    val context = LocalContext.current
    val bitmap = remember {
        mutableStateOf<Bitmap?>(null)
    }

    val launcher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.GetContent()
    ) { uri: Uri? ->
        imageUri.value = uri
    }

    imageUri.value?.let {
        LaunchedEffect(Unit) {
            if (Build.VERSION.SDK_INT < 28) {
                bitmap.value = MediaStore.Images
                    .Media.getBitmap(context.contentResolver, it)
            } else {
                val source = ImageDecoder
                    .createSource(context.contentResolver, it)
                bitmap.value = ImageDecoder.decodeBitmap(source)
            }
        }
    }

    bitmap.value?.let { btm ->
        Image(
            bitmap = btm.asImageBitmap(),
            contentDescription = null,
            modifier = Modifier.size(400.dp)
        )
    }

    Button(onClick = {
        launcher.launch("image/*")
    }) {
        Icon(Icons.Filled.PhotoAlbum, "")
    }
}

example

图像被删除(它们不会回来,这是循环gif)

PS:对于LazyColumn,我确实使用了键.我也试过使用Coil的AsyncImage,但它也有同样的问题

推荐答案

它被删除是因为当你滚动离开上传的图像时,LazyColumn会删除不再可见的项目以获得更好的性能,LazyList在引擎盖下使用子组合布局,它重新组合了可见的项目和即将在滚动方向上可见的项目,这是不可能的,因为你没有将它们保存在重组的某个地方(例如视图模型)!

您可以将URI或URI作为字符串存储在数据类中,例如

@Immutable
data class MyModel(
    val title: String,
    val description: String,
    val uri: Uri? = null
)

并创建一个ViewModel,其中包含项和在设置URI时更新URI的函数

class MyViewModel : ViewModel() {
    val items = mutableStateListOf<MyModel>()
        .apply {
            repeat(15) {
                add(MyModel(title = "Title$it", description = "Description$it"))
            }
        }

    fun update(index: Int, uri: Uri) {
        val item = items[index].copy(uri = uri)
        items[index] = item
    }
}

通过点击按钮获取URI

@Composable
fun PhotoUpload(
    onError: (() -> Unit)? = null,
    onImageSelected: (Uri) -> Unit
) {

    val launcher = rememberLauncherForActivity结果(
        contract = Activity结果Contracts.GetContent()
    ) { uri: Uri? ->
        if (uri == null) {
            onError?.invoke()
        } else {
            onImageSelected(uri)
        }

    }

    Button(onClick = {
        launcher.launch("image/*")
    }) {
        Icon(Icons.Filled.PhotoAlbum, "")
    }
}

设置后通过回调返回URI的行

@Composable
private fun MyRow(
    title: String,
    description: String,
    uri: Uri?,
    onImageSelected: (Uri) -> Unit
) {
    Column(
        modifier = Modifier
            .shadow(ambientColor = Color.LightGray, elevation = 4.dp)
            .fillMaxWidth()
            .background(Color.White, RoundedCornerShape(8.dp))
            .padding(8.dp)
    ) {
        Text(title)
        Text(description)
        uri?.let { imageUri ->
            AsyncImage(
                modifier = Modifier
                    .fillMaxWidth()
                    .aspectRatio(4 / 3f),
                model = imageUri, contentDescription = null
            )
        }
        PhotoUpload(onImageSelected = onImageSelected)
    }
}

用法

@Composable
private fun ImageUploadSample(viewModel: MyViewModel) {
    LazyColumn {

        itemsIndexed(
            key = { _, item ->
                item.hashCode()
            },
            items = viewModel.items
        ) { index, myModel ->
            MyRow(
                title = myModel.title,
                description = myModel.description,
                uri = myModel.uri,
                onImageSelected = { uri ->
                    viewModel.update(index, uri)
                }
            )
        }
    }
}

结果

enter image description here

Android相关问答推荐

如何将文本相对于喷气背包中的图标垂直居中?

如何在Jetpack Compose中使用Box Composable来实现这种布局?

如何在Jetpack composeH中创建具有弯曲末端的六边形形状

如何在Android Jetpack Compose中找到我的手机屏幕一行有多少个单词

try 用Jetpack Compose理解视图模型和导航

Jetpack Compose:带芯片的Textfield

如何显示具体的商品数量?

从包含的(复合)模块导入 Kotlin 类时,Android 应用程序模块的 build.gradle.kts 未解决的引用错误

当 Jetpack Compose 中的第一个文本很长时,将省略号添加到第一个文本

如何将一个没有 GRADLE 的古老 Android 项目导入到今天的 Android Studio 中?

在 jetpack compose 中交替使用 View.INVISIBLE

如何正确地将图像上传到 Jetpack Compose 中的 LazyList 中的项目?

在 Jetpack Compose 中重用具有重复代码的列

在事件中使用 Context/Toast 时不需要的重组 - Jetpack Compose

如何只允许拖动 BottomSheetScaffold 中 BottomContent 的 SheetPeek 的一部分?

在 Kotlin 中循环遍历字符串并用新行替换句号

compose 更改列表元素但lazyColumn不更改

在android studio中使用wifi配对设备的问题

在jetpack compose中看不到圆角

验证备份 ZIP 文件