在 Android 中不显示视图而将其转换为 Bitmap?

我会试着解释我到底需要做什么。

我有三个不同的屏幕,分别显示 A B C。还有一个叫做 HomeScreen 的屏幕,所有的3个屏幕位图都应该显示在 Gallery 视图中,用户可以选择他想要进入的视图。

我已经能够得到所有3个屏幕的位图,并显示在画廊视图中,将所有的代码在家庭屏幕活动只。现在,这使代码复杂了很多,我想简化它。

因此,我可以从 HomeScreen 调用另一个 Activity 并且不显示它,只是获取该屏幕的位图。例如,假设我只调用 HomeScreen,它调用 Activity A,B,C,但是没有显示来自 A,B,C 的任何活动。它只是通过 getDrawingCache ()给出屏幕的 Bitmap。然后我们可以在 HomeScreen 的 Gallery 视图中显示这些位图。

我希望我已经很清楚地解释了这个问题。

请告诉我这是否可行。

127067 次浏览

有一种方法可以做到这一点。你必须创建一个位图和一个画布,并调用 view.draw (画布) ;

这是密码:

public static Bitmap loadBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap( v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
v.draw(c);
return b;
}

如果视图没有显示在它的大小之前,那么它的大小将为零:

if (v.getMeasuredHeight() <= 0) {
v.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Bitmap b = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
v.draw(c);
return b;
}

编辑: 根据 这篇文章将 ABC0作为值传递给 makeMeasureSpec()没有任何好处(虽然对于一些视图类它确实工作) ,推荐的方法是:

// Either this
int specWidth = MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.AT_MOST);
// Or this
int specWidth = MeasureSpec.makeMeasureSpec(0 /* any */, MeasureSpec.UNSPECIFIED);
view.measure(specWidth, specWidth);
int questionWidth = view.getMeasuredWidth();

我的解决办法是:

public static Bitmap getBitmapFromView(View view) {
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
return returnedBitmap;
}

享受:)

试试这个,

/**
* Draw the view into a bitmap.
*/
public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);


boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);


// Reset the drawing cache background color to fully transparent
// for the duration of this operation
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);


if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
return null;
}


Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);


// Restore the view
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);


return bitmap;
}

我知道这可能是一个陈旧的问题,但我有困难得到这些解决方案为我工作。 具体来说,我发现如果在视图膨胀之后对其进行了任何更改,那么这些更改将不会合并到呈现的位图中。

这就是最终在我的案子中起作用的方法。但有一点需要注意。在调用 getViewBitmap(View)之前,我膨胀了我的视图,并要求它以已知的尺寸布局。这是必要的,因为我的视图布局将使其高度/宽度为零,直到内容被放置在里面。

View view = LayoutInflater.from(context).inflate(layoutID, null);
//Do some stuff to the view, like add an ImageView, etc.
view.layout(0, 0, width, height);


Bitmap getViewBitmap(View view)
{
//Get the dimensions of the view so we can re-layout the view at its current size
//and create a bitmap of the same size
int width = view.getWidth();
int height = view.getHeight();


int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);


//Cause the view to re-layout
view.measure(measuredWidth, measuredHeight);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());


//Create a bitmap backed Canvas to draw the view into
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);


//Now that the view is laid out and we have a canvas, ask the view to draw itself into the canvas
view.draw(c);


return b;
}

对我来说,“神奇的酱汁”就是在这里找到的: Https://groups.google.com/forum/#!topic/android-developers/bxibaoeta1q

干杯,

利瓦伊

希望这个能帮上忙

View view="some view instance";
view.setDrawingCacheEnabled(true);
Bitmap bitmap=view.getDrawingCache();
view.setDrawingCacheEnabled(false);

更新
在 API 级别28中不推荐使用 getDrawingCache()方法。因此,请为 API 级别 > 28寻找其他替代方法。

view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);

我觉得这样好一点:

/**
* draws the view's content to a bitmap. code initially based on :
* http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
*/
@Nullable
public static Bitmap drawToBitmap(final View viewToDrawFrom, int width, int height) {
boolean wasDrawingCacheEnabled = viewToDrawFrom.isDrawingCacheEnabled();
if (!wasDrawingCacheEnabled)
viewToDrawFrom.setDrawingCacheEnabled(true);
if (width <= 0 || height <= 0) {
if (viewToDrawFrom.getWidth() <= 0 || viewToDrawFrom.getHeight() <= 0) {
viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
width = viewToDrawFrom.getMeasuredWidth();
height = viewToDrawFrom.getMeasuredHeight();
}
if (width <= 0 || height <= 0) {
final Bitmap bmp = viewToDrawFrom.getDrawingCache();
final Bitmap result = bmp == null ? null : Bitmap.createBitmap(bmp);
if (!wasDrawingCacheEnabled)
viewToDrawFrom.setDrawingCacheEnabled(false);
return result;
}
viewToDrawFrom.layout(0, 0, width, height);
} else {
viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
}
final Bitmap drawingCache = viewToDrawFrom.getDrawingCache();
final Bitmap bmp = ThumbnailUtils.extractThumbnail(drawingCache, width, height);
final Bitmap result = bmp == null || bmp != drawingCache ? bmp : Bitmap.createBitmap(bmp);
if (!wasDrawingCacheEnabled)
viewToDrawFrom.setDrawingCacheEnabled(false);
return result;
}

使用上面的代码,如果你想使用视图本身,你不必指定位图的大小(宽度和高度使用0)。

另外,如果您希望将特殊视图(例如 SurfaceView、 Surface 或 Window)转换为位图,则应考虑使用 像素复制 类。但它需要 API 24及以上的标准。我以前不知道怎么做。

位图的布局或视图:

 private Bitmap createBitmapFromLayout(View tv) {
int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
tv.measure(spec, spec);
tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(tv.getMeasuredWidth(), tv.getMeasuredWidth(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
c.translate((-tv.getScrollX()), (-tv.getScrollY()));
tv.draw(c);
return b;
}

调用方法:

Bitmap src = createBitmapFromLayout(View.inflate(this, R.layout.sample, null)/* or pass your view object*/);

在 Android KTX: View.drawToBitmap(Bitmap.Config)中有一个很棒的 Kotlin 扩展功能

我几天前刚用过这个:

fun generateBitmapFromView(view: View): Bitmap {
val specWidth = View.MeasureSpec.makeMeasureSpec(1324, View.MeasureSpec.AT_MOST)
val specHeight = View.MeasureSpec.makeMeasureSpec(521, View.MeasureSpec.AT_MOST)
view.measure(specWidth, specHeight)
val width = view.measuredWidth
val height = view.measuredHeight
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.layout(view.left, view.top, view.right, view.bottom)
view.draw(canvas)
return bitmap
}

此代码基于此 大意

private fun getBitmapFromView(view: View): Bitmap
{
val returnedBitmap = Bitmap.createBitmap(view.width,
view.height
,Bitmap.Config.ARGB_8888)


val canvas = Canvas(returnedBitmap)


//background image
val bgDrawable = view.background


//background image is selected
if (bgDrawable != null){
bgDrawable.draw(canvas)
}
else{
canvas.drawColor(Color.WHITE)
}
    

view.draw(canvas)
    

return returnedBitmap


}

我也有类似的需求,并且根据提供的代码开发了一些东西,特别是@Azhagthott 和全新的 androidx.core.view.draToBitmap,希望这里也有希望,

val view = MyCustomView(context)
view.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST)
)
view.layout(0, 0, width, height)
val bitmap = view.drawToBitmap()

我在项目中遇到了同样的问题,并找到了一个解决方案,我将在这里描述。

public Bitmap catchBitmapFromView(View capture_view){
if (capture_view == null) {
return null;
}


capture_view.setDrawingCacheEnabled(true);


Bitmap bitmap = Bitmap.createBitmap(capture_view.getWidth(), capture_view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Drawable bgDrawable = capture_view.getBackground();
if (bgDrawable != null) {
bgDrawable.draw(canvas);
} else {
canvas.drawColor(Color.WHITE);
}
capture_view.draw(canvas);


capture_view.setDrawingCacheEnabled(false);
return bitmap;
}