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

标签 android kotlin android-jetpack-compose lazycolumn

我想让用户将图像添加到 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 在引擎盖下使用 SubcomposeLayout 重新组合可见项目和将在滚动方向可见的项目,这是不可能的,因为您没有将它们保存在重组之外的某个地方(例如 View 模型)!

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

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

然后创建一个包含项目的 ViewModel 和一个在设置时更新 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 = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.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 中的 LazyList 中的项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74678368/

相关文章:

java - 仅将前几百个样本从输入流读入字节数组(其余为零)

Android Studio 模拟器文件权限被拒绝

android - Google Play 服务已过时。需要 4030500 但找到 3266132

java - 在 kotlin 中找不到类?

kotlin - Jetpack Compose 中的装饰框 BasicTextField

android - 丹麦语的 "values"文件夹名称是什么?

android - 将 Paging 3 alpha 更新为稳定导致索引问题 Android

android-studio - 将文件移动到Android Studio中的另一个程序包后,如何防止自动格式化?

android - Jetpack 撰写 : TextField clickable does not work

android - Jetpack 撰写 : Could not set unknown property 'useIR'