我正在尝试保存当前活动的屏幕截图,但不是整个视图,只是其中的一部分。 就我而言: 我的活动
在附图中,我想保存从视图 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..
有人可以帮助我吗?也许有更好的方法来实现我的目标? 谢谢!
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 中的解决方案,图形修改器页面上有官方示例。