These snippets allows grabbing a screenshot of a View
or Activity
as a bitmap.
There are special version to make this work on SurfaceView
s and TextureView
s.
To grab a complete Activity
, simply apply the snippets below on its root view.
Simple, old method
view.isDrawingCacheEnabled = true
val sourceBitmap = view.drawingCache
val bitmap = sourceBitmap.copy(sourceBitmap.config, false)
These methods are deprecated, but still work. Note that it might not even be necessary to clone the Bitmap, e.g. if you write it directly to a file before it is recycled or modified.
New method (Android O and above)
This is supposed to work a lot better with SurfaceViews
, but I have had no success grabbing a still
frame from an ExoPlayer that uses a SurfaceView
. However, if you set up ExoPlayer to use a TextureView
instead,
this method works, you should use the PixelCopy
API:
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
PixelCopy.request(
window,
Rect(
locationOfViewInWindow[0],
locationOfViewInWindow[1],
locationOfViewInWindow[0] + view.width,
locationOfViewInWindow[1] + view.height
), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap)
}
},
Handler()
)
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
e.printStackTrace()
}
TextureView special
The above method works with a TextureView
as well, but if it is only a TextureView you’re interested in, there is
a shortcut:
val bitmap = textureView.bitmap
Wrapping it all together
In one monster snippet. window
is a field availablt in the context of an Activity
,
so use requireActivity().window
when this is used in a Fragment
.
fun createScreenshot(view: View, callback: (Bitmap) -> Unit) {
if (view is TextureView) {
callback(view.bitmap.copy(view.bitmap.config, false))
return
}
window?.let { window ->
val locationOfViewInWindow = IntArray(2)
view.getLocationInWindow(locationOfViewInWindow)
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
PixelCopy.request(
window,
Rect(
locationOfViewInWindow[0],
locationOfViewInWindow[1],
locationOfViewInWindow[0] + view.width,
locationOfViewInWindow[1] + view.height
), bitmap, { copyResult ->
if (copyResult == PixelCopy.SUCCESS) {
callback(bitmap)
}
},
Handler()
)
} else {
view.isDrawingCacheEnabled = true
callback(view.drawingCache.copy(view.drawingCache.config, false))
}
} catch (e: IllegalArgumentException) {
// PixelCopy may throw IllegalArgumentException, make sure to handle it
e.printStackTrace()
}
}
}