簡體   English   中英

如何正確地將圖像上傳到 Jetpack Compose 中的 LazyList 中的項目?

[英]How to correctly upload image to an item in LazyList in Jetpack Compose?

我想讓用戶將圖像添加到 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, "")
    }
}

例子

圖片被刪除(他們不會回來,這是一個循環 gif)

PS:對於 LazyColumn,我確實使用鍵。 我也嘗試使用 Coil 的 AsyncImage,但它有同樣的問題

它被刪除是因為當您從上傳的圖像滾動時,LazyColumn 刪除不再可見的項目以獲得更好的性能,LazyList 在引擎蓋下使用 SubcomposeLayout 重新組合可見項目和將在滾動方向可見的項目,這是不可能,因為您沒有將它們保存在重組之外的某個地方(例如視圖模型)!

您可以將 Uris 或 Uris 作為字符串存儲在數據 class 中,例如

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

並創建一個包含項目的 ViewModel 和一個 function 以在設置時更新 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)
                }
            )
        }
    }
}

結果

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM