在Android API 28中,view.getDrawingCache()已经被弃用。

49

在Android API 28中,view.getDrawingCache()已被弃用。是否有更新的解决方案来生成Android中特定视图的位图?

8个回答

75

获取视图的位图有两种方法:

  1. 使用Canvas
  2. 使用Pixel Api

Canvas Java

Bitmap getBitmapFromView(View view) {
    Bitmap bitmap = Bitmap.createBitmap(
        view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888
    );
    Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);
    return bitmap;
}

Bitmap getBitmapFromView(View view,int defaultColor) {
    Bitmap bitmap = Bitmap.createBitmap(
        view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888
    );
    Canvas canvas = new Canvas(bitmap);
    canvas.drawColor(defaultColor);
    view.draw(canvas);
    return bitmap;
}

Canvas Kotlin

fun getBitmapFromView(view: View): Bitmap {
    val bitmap = Bitmap.createBitmap(
        view.width, view.height, Bitmap.Config.ARGB_8888
    )
    val canvas = Canvas(bitmap)
    view.draw(canvas)
    return bitmap
}

fun getBitmapFromView(view: View, defaultColor: Int): Bitmap {
    val bitmap = Bitmap.createBitmap(
        view.width, view.height, Bitmap.Config.ARGB_8888
    )
    val canvas = Canvas(bitmap)
    canvas.drawColor(defaultColor)
    view.draw(canvas)
    return bitmap
}

示例

//@param rootView is View object which you want to get bitmap
Bitmap bitmap = getBitmapFromView(rootView);
Bitmap bitmapColored = getBitmapFromView(rootView,Color.WHITE);

PixelCopy Api

https://dev59.com/8VQJ5IYBdhLWcg3w_7O7#52985554

fun getBitmapFromView(view: View, activity: Activity, callback: (Bitmap) -> Unit) {
    activity.window?.let { window ->
        val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
        val locationOfViewInWindow = IntArray(2)
        view.getLocationInWindow(locationOfViewInWindow)
        try {
            PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
                if (copyResult == PixelCopy.SUCCESS) {
                    callback(bitmap)
                }
                // possible to handle other result codes ...
            }, Handler())
        } catch (e: IllegalArgumentException) {
            // PixelCopy may throw IllegalArgumentException, make sure to handle it
            e.printStackTrace()
        }
    }
}

了解更多请参见关于

位图(Bitmap)

画布(Canvas)


如何获取视图的一部分?createBitmap似乎只接受宽度和高度参数,我想要的是x、y、宽度和高度。 - Alex
@Alex 用户,这是 Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height) - Ashvin solanki
现在该如何获取源代码呢?因为view.getDrawingCache()已经被弃用了,而它曾经返回位图。 - Alex
@Alex 首先使用此方法获取视图的位图,然后根据需要进行修改。 - Ashvin solanki
Kotlin中有一个View.drawToBitmap扩展函数,它考虑了scrollX/Y的影响。 - Xixiaxixi

14

我已经找到了一种使用PixelCopy API来获取视图为位图的方法。使用了Kotlin。

fun getBitmapFromView(view: View, activity: Activity, callback: (Bitmap) -> Unit) {
    activity.window?.let { window ->
        val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
        val locationOfViewInWindow = IntArray(2)
        view.getLocationInWindow(locationOfViewInWindow)
        try {
            PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
                if (copyResult == PixelCopy.SUCCESS) {
                    callback(bitmap)
                }
                // possible to handle other result codes ...
            }, Handler())
        } catch (e: IllegalArgumentException) {
            // PixelCopy may throw IllegalArgumentException, make sure to handle it
            e.printStackTrace()
        }
    }
}

ref - olfek
24
为什么谷歌总是要把事情搞得复杂化?我想在调用方法的同时得到位图,而不是在将来使用回调函数。 - TheRealChx101
2
@TheRealChx101 今天我发现了这个,我打算使用它代替。 - olfek
1
PixelCopy 需要 API 级别 26 及以上。如果您需要兼容旧的 API 级别,请使用 @daka 发布的解决方案。 - Morgan Koh
1
@daka 你可以使用这个库链接。它可以处理保存视图图像的所有事项。 - Mostafa Monowar
一个更好和优化的解决方案是“view.drawToBitmap()”。 - Othmane_lam

3

试试这个:

    private fun convertViewToDrawable(view: View): Bitmap {
    val spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
    view.measure(spec, spec)
    view.layout(0, 0, view.measuredWidth, view.measuredHeight)
    val b = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight,
            Bitmap.Config.ARGB_8888)
    val c = Canvas(b)
    c.translate((-view.scrollX).toFloat(), (-view.scrollY).toFloat())
    view.draw(c)
    return b
}

翻译和滚动值有什么必要? - android developer
如果没有它,如果视图被滚动,写入位图的视图部分将不会与实际可见的视图部分匹配。 - Brian Rak

2

我需要使用SurfaceView才能使用PixelCopy()吗?因为在Android文档中它说“像素复制请求允许从Surface到Bitmap进行复制操作”。 - Mostafa Monowar
添加一个 pixelCopy() 的示例来捕获视图的位图。 - Ashvin solanki
1
@Ashvinsolanki,请检查一下我的答案。它可以正常工作。 - Mostafa Monowar
如何使用:https://medium.com/@hiteshkrsahu/a-complete-guide-for-taking-screenshot-in-android-28-bcb9a19a2b6e - Nick Kovalsky
使用PixelCopy不一定是“必须的”。文档只建议在UI反馈报告和单元测试中使用它。 - mr5

1
很精确的代码...
private fun convertViewToDrawable(view: View): Bitmap {
        val b = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight,
            Bitmap.Config.ARGB_8888)
        val c = Canvas(b)
        c.translate((-view.scrollX).toFloat(), (-view.scrollY).toFloat())
        view.draw(c)
        return b
    }

2
为什么需要翻译和滚动值? - android developer

0
Kotlin 代码与视图膨胀:
fun getBitmapFromView(layoutInflater: LayoutInflater): Bitmap =
layoutInflater.inflate(R.layout.layoutID, null).run {
    //Bind data If you needed Example - [findViewById<TextView>(R.id.viewId).text = data]
    measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    layout(0, 0, measuredWidth, measuredHeight)
    val bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    draw(canvas)
    bitmap
}

可以像这样获取layoutInflater,

  1. 在活动或片段内部 -
    this.layoutInflater

  2. 在活动或片段外部 -
    val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater


0
bitmap = view.drawToBitmap()
val pixel = bitmap.getpixel(x,y)

虽然这段代码可能解决了问题,但是包括解释它如何以及为什么解决了问题将有助于提高您的帖子质量,并可能导致更多的赞。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 - Yunnosch

0

其他一些 Kotlin 代码(ScrollView 情况下)

val ScrollView.bitmap: Bitmap
get() {
    val bitmap = Bitmap.createBitmap(width, getChildAt(0).height, Bitmap.Config.RGB_565)
    with(Canvas(bitmap)) {
        val background = background
        if (background != null) {
            background.draw(this)
        } else {
            drawColor(Color.WHITE)
        }
        draw(this)
    }
    return bitmap
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接