Kadir Can
Kadir Can

Reputation: 11

preloading images in coil-jetpack compose

I use lazycolumn to display amount of images using coil lets say 10 image, when I reach the end of lazycolumn I get 10 more images, but the images are not loaded from the network yet and the the images has crossfade which I don't want, is there a way to make images loading after all new incoming images cached so I can see fully visible images instead of crossfade or place holder...

the thing i want to get is the scroll behavior of social media apps like instagram, when we scroll down to bottom if the items finish we don't see a placeholder or crossfade, instead we see a loading indicator until all data is being cached,it will be visible to us when it is cached, and after it has been cached even if the amount of items that lazy column has are too many we still can see the images at the top (when i scroll bottom and turn back to top I see images are reloaded from network in my case )


@Composable
fun ProductScreen(
    viewModel: ViewModel = hiltViewModel()
) {
    val products by viewModel.products.collectAsStateWithLifecycle()
    val isLoading by viewModel.isLoading.collectAsStateWithLifecycle()

    val listState = rememberLazyListState()
    val shouldLoadMore = remember {
        derivedStateOf {
            val totalITemsCount = listState.layoutInfo.totalItemsCount
            val lastVisibleItemIndex =
                listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
            !isLoading && lastVisibleItemIndex >= totalITemsCount - 1
        }
    }

    LaunchedEffect(shouldLoadMore.value) {
        if (shouldLoadMore.value) {
            val totalItemCount = listState.layoutInfo.totalItemsCount
            viewModel.loadMoreProducts(totalItemCount)
        }
    }
    val context = LocalContext.current


    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .padding(horizontal = 16.dp),
        state = listState,
        verticalArrangement = Arrangement.spacedBy(5.dp)
    ) {
        items(products) { product ->
            ProductCard(product, context = context)
        }
        if (isLoading) {
            item {
                Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
                    CircularProgressIndicator()
                }
            }
        }
    }
}

@Composable
fun ProductCard(product: Product, context: Context) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(12.dp)
            .aspectRatio(1f)
            .border(1.dp, Color.Blue.copy(alpha = 0.3f), shape = RoundedCornerShape(6.dp))
    ) {
        AsyncImage(
            model = ImageRequest.Builder(context)
                .data(product.imageUrl)
                .crossfade(false)
                .build(),
            contentDescription = "",
            modifier = Modifier.fillMaxSize(),

            )
    }
}

Upvotes: 1

Views: 246

Answers (2)

Milad Mohammadi
Milad Mohammadi

Reputation: 54

Thanks to Công Hải. This is how you can preload and use the image:

val context = LocalContext.current
val imageLoader = ImageLoader.Builder(context).build()
val imageData = ImageRequest.Builder(LocalContext.current)
    .data(imageUrl)
    .placeholder(placeholderResourceId) // Image res id which will be used as a placeholder
    .error(errorResourceId) // Image res id which will be used if image is not loaded based on any error
    .build()

SubcomposeAsyncImage(
    model = imageData,
    contentDescription = "contentDescription",
    imageLoader = imageLoader,
    success = { state ->
        Image(
            modifier = modifier,
            painter = state.painter,
            contentDescription = "contentDescription",
        )
    }

Upvotes: 0

Công Hải
Công Hải

Reputation: 5241

to preload logic you can use this code, and make sure it runs success after you append new items to LazyColumn

val imageLoader = Coil.imageLoader(context)
val request = LoadRequest.Builder(context)
    .data("your_link")
    .target { drawable ->
        val bitmap = (drawable as BitmapDrawable).bitmap // bitmap from cache returns
    }
    .build()
imageLoader.execute(request)

Upvotes: 0

Related Questions