如何在Android compose中截取完整屏幕截图?

问题描述 投票:0回答:2

我正在使用 Jetpack Compose 开发一个 Android 应用程序。

我有一个简单的页面。 它有一个可滚动的列,例如:

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)
            }
        }
    }
}

其实

dataMap
并不简单,它有嵌套列表。 反正
dataMap
的尺寸有限,没有那么大。 所以我只使用 Column 而不是 LazyColumn。

我有一个 FAB 按钮来共享屏幕。 我可以在当前屏幕上编写代码,并且工作正常。

但问题是它只截取当前可见区域而不是完全滚动的区域。

我的

takeScreenshot
功能在这里:

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
}

这被称为:

@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)
        }
    }
}
android kotlin android-jetpack-compose screenshot
2个回答
1
投票

看看这个 jetpack-composable-to-bitmap-image

您可以膨胀一个无界的 AndroidView 并使用

drawToBitmap
将其转换为位图

@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
}

并从 onClick 方法所在的位置声明

screenshotableComposable
,您可以使用
screenshotableComposable.invoke()
从 onClick 调用它,它将返回位图

val screenshotableComposable = screenshotableComposable(
    content = {
        /*...composable content...*/
    }
)


onClick = {
    val bitmap = screenshotableComposable.invoke()
}

存在一个问题,您需要绘制内容两次,一次实际在屏幕上渲染,另一次在

screenshotableComposable

内渲染

0
投票

从 Compose 1.6.0-alpha01+ 开始,Compose 中有一种新的本机方法可以执行此操作:https://developer.android.com/jetpack/compose/graphics/draw/modifiers#composable-to-bitmap

Column(
    modifier = Modifier
        .padding(padding)
        .fillMaxSize()
        .drawWithCache {
            // Example that shows how to redirect rendering to an Android Picture and then
            // draw the picture into the original destination
            val width = this.size.width.toInt()
            val height = this.size.height.toInt()

            onDrawWithContent {
                val pictureCanvas =
                    androidx.compose.ui.graphics.Canvas(
                        picture.beginRecording(
                            width,
                            height
                        )
                    )
                // requires at least 1.6.0-alpha01+
                draw(this, this.layoutDirection, pictureCanvas, this.size) {
                    [email protected]()
                }
                picture.endRecording()

                drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
            }
        }

) {
    ScreenContentToCapture()
}

将图片转换为位图:

val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    Bitmap.createBitmap(picture)
} else {
    val bitmap = Bitmap.createBitmap(
        picture.width,
        picture.height,
        Bitmap.Config.ARGB_8888
    )
    val canvas = android.graphics.Canvas(bitmap)
    canvas.drawColor(android.graphics.Color.WHITE)
    canvas.drawPicture(picture)
    bitmap
}
© www.soinside.com 2019 - 2024. All rights reserved.