【问题标题】:Take screenshot of a composable fun programmatically in Jetpack Compose在 Jetpack Compose 中以编程方式截取可组合乐趣的屏幕截图
【发布时间】:2021-07-13 02:58:11
【问题描述】:

我想将 Jetpack compose 发出的 UI 捕获为位图。在 XML 中是这样完成的:

基本上将视图作为输入参数并将其作为位图返回。

//take screenshot of the view added as an input argument
fun takeScreenShot(view: View) : Bitmap {
    val bitmap = Bitmap.createBitmap(
        view.width,
        view.height,
        Bitmap.Config.ARGB_8888
    )
    val canvas = Canvas(bitmap)
    view.draw(canvas)
    return bitmap
}

在 Jetpack compose 中相当于什么?

【问题讨论】:

标签: android android-jetpack-compose android-jetpack


【解决方案1】:

测试中可以从可组合项中截取屏幕截图。
如需在生产代码中截屏,请参阅this questionthis issue

首先,确保您的构建脚本中有以下依赖项(以及其他必需的 Compose 依赖项):

debugImplementation("androidx.compose.ui:ui-test-manifest:<version>")

注意:除了上面的依赖,你可以简单地在androidTest目录中添加一个AndroidManifest.xml,然后在manifest>@987654328中添加以下内容@元素:&lt;activity android:name="androidx.activity.ComponentActivity" /&gt;.
参考this answer

以下是保存、读取和比较屏幕截图的完整示例:
(设置写权限等测试请参考this post

class ScreenshotTest {

    @get:Rule val composeTestRule = createComposeRule()

    @Test fun takeAndSaveScreenshot() {
        composeTestRule.setContent { MyComposableFunction() }
        val node = composeTestRule.onRoot()
        val screenshot = node.captureToImage().asAndroidBitmap()
        saveScreenshot("screenshot.png", screenshot)
    }

    @Test fun readAndCompareScreenshots() {
        composeTestRule.setContent { MyComposableFunction() }
        val node = composeTestRule.onRoot()
        val screenshot = node.captureToImage().asAndroidBitmap()

        val context = InstrumentationRegistry.getInstrumentation().targetContext
        val path = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        val file = File(path, "screenshot.png")
        val saved = readScreenshot(file)

        println("Are screenshots the same: ${screenshot.sameAs(saved)}")
    }

    private fun readScreenshot(file: File) = BitmapFactory.decodeFile(file.path)

    private fun saveScreenshot(filename: String, screenshot: Bitmap) {
        val context = InstrumentationRegistry.getInstrumentation().targetContext
        // Saves in /Android/data/your.package.name.test/files/Pictures on external storage
        val path = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        val file = File(path, filename)
        file.outputStream().use { stream ->
            screenshot.compress(Bitmap.CompressFormat.PNG, 100, stream)
        }
    }
}

感谢 Google Codelabs 提供this

【讨论】:

    【解决方案2】:

    我会看看 JP-Compose 测试是如何做到这一点的。

    android-compose-codelab 是一个很好的起点,请参阅:

    /**
     * Simple on-device screenshot comparator that uses golden images present in
     * `androidTest/assets`. It's used to showcase the [AnimationClockTestRule] used in
     * [AnimatingCircleTests].
     *
     * Minimum SDK is O. Densities between devices must match.
     *
     * Screenshots are saved on device in `/data/data/{package}/files`.
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun assertScreenshotMatchesGolden(
        goldenName: String,
        node: SemanticsNodeInteraction
    ) {
        val bitmap = node.captureToImage().asAndroidBitmap()
    }
    

    来自ScreenshotComparator.kt。您可以在AndroidHelpers.kt 中找到captureToImage()

    您还可以在这里找到ImageBitmap.kt,其中asAndroidBitmap() 仅确保ImageBitmap 的底层“通用”版本实际上是Android 上的android.graphics.Bitmap(这是为了使代码与平台无关,以便它也可以在 JVM/桌面上运行)

    【讨论】:

    • 我们可以通过这种方式以编程方式访问屏幕截图吗?执行诸如将其上传到云存储之类的操作
    猜你喜欢
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2023-03-25
    • 1970-01-01
    • 2014-04-17
    • 1970-01-01
    相关资源
    最近更新 更多