在 Android 上保存自定义视图的屏幕截图

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

我正在尝试保存当前活动的屏幕截图,但不是整个视图,只是其中的一部分。 就我而言: 我的活动

在附图中,我想保存从视图 B、C 和 D 构造的位图。

B 是线性布局,C 是纯位图,D 是相对布局。

据我了解,一种方法是创建画布,将所有“元素”添加到其中,最后获得所需的自定义位图。

我在使用以下代码时遇到问题:

iViewBHeight= viewB.getHeight();
// Prepare empty bitmap as output
Bitmap result = Bitmap.createBitmap(bitmapC.getWidth(),bitmapC.getHeight() +     iViewBHeight, Config.ARGB_8888);
// Flush source image into canvas
Canvas canvas = new Canvas(result);
// Draw bitmap C to canvas 'under' view B
canvas.drawBitmap(bitmapC, 0, iViewBHeight, null);
// Draw view B to canvas
viewB.setDrawingCacheEnabled(true);
viewB.buildDrawingCache(true);
canvas.drawBitmap(Bitmap.createBitmap(viewB.getDrawingCache()), 0, 0, null);
viewB.setDrawingCacheEnabled(false);

// Desired bitmap is at 'result'

结果是位图C绘制好了,但是视图B太大,扩展了位图。 我没有尝试添加视图 D..

有人可以帮助我吗?也许有更好的方法来实现我的目标? 谢谢!

android android-layout bitmap android-canvas screenshot
1个回答
3
投票

View
的绘图缓存已经被弃用了一段时间,无论如何,对于这样的东西来说,它从来都不是一个好主意,尽管它似乎是所有可用示例所演示的(包括我的示例)。

搞乱缓存一开始有点愚蠢,因为任何使用这种方法的

View
也可以直接绘制到我们自己的
Canvas
Bitmap
,因此也强制
View
在内部执行此操作是多余和浪费的。

我们可以通过允许由其包含的一组

View
来定义所需的图像边界来进一步简化事情,而不是为特定设置进行繁琐的算术。基于
Window
的装饰
View
进行边界计算使事情变得更加容易,并且允许我们捕获
Activity
的几乎任何部分,即使我们不拥有所有内容;例如,就像自动提供
ActionBar
时一样。

import android.app.Activity
import android.graphics.Bitmap
import android.graphics.Rect
import android.view.View
import androidx.core.graphics.applyCanvas
import androidx.core.graphics.withTranslation

fun Activity.captureToBitmap(
    vararg boundedViews: View,
    config: Bitmap.Config = Bitmap.Config.ARGB_8888
): Bitmap {
    val bounds = Rect()
    val viewBounds = Rect()
    val viewLocation = IntArray(2)
    boundedViews.forEach { view ->
        view.getLocationInWindow(viewLocation)
        viewBounds.set(0, 0, view.width, view.height)
        viewBounds.offset(viewLocation[0], viewLocation[1])
        bounds.union(viewBounds)
    }
    return drawToBitmap(bounds, config)
}

fun Activity.drawToBitmap(
    bounds: Rect,
    config: Bitmap.Config = Bitmap.Config.ARGB_8888
): Bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), config)
    .applyCanvas {
        val x = -bounds.left.toFloat()
        val y = -bounds.top.toFloat()
        withTranslation(x, y, window.decorView::draw)
    }

我不确定问题布局中的确切设置,但如果

B
包含
C
D
,那么调用
captureToBitmap(viewB)
就足够了。否则,列出所有内容以确保确实没有什么坏处:

val bitmap = captureToBitmap(viewB, viewC, viewD)

当然,您应该在单独的线程或协程上执行此操作,但请注意在脱离主线程时不要修改任何

View

如果您需要 Compose 中的解决方案,图形修改器页面上有官方示例

© www.soinside.com 2019 - 2024. All rights reserved.