Hey, I'm trying to create a PDF viewer composable ...
# compose
f
Hey, I'm trying to create a PDF viewer composable using the PdfRenderer and Coil for loading the bitmaps into a 
LazyColumn
. See thread for code. I kind of got it working, however when the bitmap is first loaded (i.e. it doesn't come from the cache), it won't display in the list until I scroll (i.e. after a redraw). I want to make use of the features of 
LazyColumn
 and only load the PDF pages when they become visible. Is there any better way to achieve this?
Copy code
@Composable
fun PdfViewer(
	modifier: Modifier = Modifier,
	uri: Uri,
	verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp)
) {
	val loaderScope = rememberCoroutineScope()
	val renderer = remember(uri) {
		val input = ParcelFileDescriptor.open(uri.toFile(), ParcelFileDescriptor.MODE_READ_ONLY)
		PdfRenderer(input)
	}
	val context = LocalContext.current
	val mutex = remember { Mutex() }
	val imageLoader = LocalContext.current.imageLoader
	BoxWithConstraints(modifier = modifier.fillMaxWidth()) {
		val width = with(LocalDensity.current) { maxWidth.toPx() }.toInt()
		val height = (width * sqrt(2f)).toInt()
		LazyColumn(
			verticalArrangement = verticalArrangement
		) {
			items(
				count = renderer.pageCount,
				key = { it }
			) { index ->
				val cacheKey = MemoryCache.Key("$uri-$index")
				val bitmap = remember(uri, index) {
					val cachedBitmap = imageLoader.memoryCache[cacheKey]
					if (cachedBitmap != null) cachedBitmap else {
						val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
						loaderScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
							mutex.withLock {
								Timber.d("Loading $uri - page $index")
								renderer.openPage(index).use {
									it.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
								}
							}
						}
						bitmap
					}
				}
				val request = ImageRequest.Builder(context)
					.size(width, height)
					.memoryCacheKey(cacheKey)
					.data(bitmap)
					.build()

				Image(
					modifier = Modifier.background(Color.White).aspectRatio(1f / sqrt(2f)).fillMaxWidth(),
					contentScale = ContentScale.Fit,
					painter = rememberImagePainter(request),
					contentDescription = "Page ${index + 1} of ${renderer.pageCount}"
				)
			}
		}
	}
}