I am developing an android app using Jetpack Compose.
I have a simple page. It has a one scrollable Column like:
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.fillMaxSize()
.padding(it)
.padding(bottom = 32.dp)
) {
if (!dataMap.isNullOrEmpty()) {
dataMap.entries.forEachIndexed { index, (key, value) ->
val header = key
val list = value
Text(text = title)
list.forEach { item ->
ItemUi(item)
}
}
}
}
Actually the dataMap
is not simple, it has nested list.
Anyway the size of the dataMap
is limited, it's not that big.
So I just use Column not LazyColumn.
And I have a FAB button to share the screen. I can write the code take current screen and it works fine.
But the problem is that it only takes a screenshot current visible area not the fully scrolled area.
My takeScreenshot
function is here:
private fun takeScreenShot(view: View, dir: File): File? {
try {
view.isDrawingCacheEnabled = true
val bitmap: Bitmap = Bitmap.createBitmap(view.drawingCache)
view.isDrawingCacheEnabled = false
val dateText = DateFormat.format("yyyy-MM-dd_hh:mm:ss", Date())
val imageFile = File("$dir/result-$dateText.jpeg")
FileOutputStream(imageFile).use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos)
fos.flush()
}
return imageFile
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
return null
}
and this is called with:
@Composable
fun MyScreen() {
val activity = LocalContext.current as Activity
val requestPermissionLauncher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
takeScreenShot(activity.window.decorView.rootView, activity.filesDir)
}
}
}
Check this out jetpack-composable-to-bitmap-image
You can inflate an unbounded AndroidView and use drawToBitmap
to convert it into bitmap
@Composable
fun screenshotableComposable(content : @Composable () -> Unit): () -> Bitmap {
val context = LocalContext.current
val composeView = remember { ComposeView(context = context) }
fun captureBitmap(): Bitmap = composeView.drawToBitmap()
AndroidView(
factory = {
composeView.apply {
setContent {
content()
/*...content...*/
}
}
},
modifier = Modifier.wrapContentSize(unbounded = true) // Make sure to set unbounded true to draw beyond screen area
)
return ::captureBitmap
}
and from where onClick method is present, declare screenshotableComposable
which you call from onClick with screenshotableComposable.invoke()
and it will return bitmap
val screenshotableComposable = screenshotableComposable(
content = {
/*...composable content...*/
}
)
onClick = {
val bitmap = screenshotableComposable.invoke()
}
There is an issue with that you need to draw content twice, one which actually renders on screen and other which renders within screenshotableComposable