将视图转换为位图而不在 Android 中显示它?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2801116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Converting a view to Bitmap without displaying it in Android?
提问by sunil
I will try to explain what exactly I need to do.
我将尝试解释我到底需要做什么。
I have 3 separate screens say A,B,C. There is another screen called say HomeScreen where all the 3 screens bitmap should be displayed in Gallery view and the user can select in which view does he wants to go.
我有 3 个独立的屏幕,比如 A、B、C。还有一个叫做 say HomeScreen 的屏幕,所有 3 个屏幕的位图都应该显示在画廊视图中,用户可以选择他想要去的视图。
I have been able to get the Bitmaps of all the 3 screens and display it in Gallery view by placing all the code in HomeScreen Activity only. Now, this has complicated the code a lot and I will like to simplify it.
通过仅将所有代码放置在 HomeScreen Activity 中,我已经能够获取所有 3 个屏幕的位图并将其显示在图库视图中。现在,这使代码变得很复杂,我想简化它。
So, can I call another Activity from HomeScreen and do not display it and just get the Bitmap of that screen. For example, say I just call HomeScreen and it calls Activity A,B,C and none of the Activities from A,B,C are displayed. It just gives the Bitmap of that screen by getDrawingCache(). And then we can display those bitmaps in Gallery view in HomeScreen.
那么,我可以从 HomeScreen 调用另一个 Activity 并且不显示它而只获取该屏幕的位图。例如,假设我只调用 HomeScreen 并且它调用了 Activity A、B、C,并且没有显示 A、B、C 中的任何活动。它只是通过 getDrawingCache() 给出该屏幕的位图。然后我们可以在 HomeScreen 的 Gallery 视图中显示这些位图。
I hope I have explained the problem very clearly.
我希望我已经非常清楚地解释了这个问题。
Please let me know if this is actually possible.
请让我知道这是否真的可能。
回答by Simon
there is a way to do this. you have to create a Bitmap and a Canvas and call view.draw(canvas);
有一种方法可以做到这一点。你必须创建一个位图和一个画布并调用 view.draw(canvas);
here is the code:
这是代码:
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 the view wasn't displayed before the size of it will be zero. Its possible to measure it like this:
如果视图在它的大小之前没有显示为零。可以这样测量:
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;
}
EDIT: according to this post, Passing WRAP_CONTENT
as value to makeMeasureSpec()
doesn't to do any good(although for some view classes it does work), and the recommended method is:
编辑:根据这篇文章,作为值传递WRAP_CONTENT
给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();
回答by Gil SH
here is my solution:
这是我的解决方案:
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;
}
Enjoy :)
享受 :)
回答by Dwivedi Ji
Try this,
尝试这个,
/**
* 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;
}
回答by levigroker
I know this may be a stale issue, but I was having problems getting any of these solutions to work for me. Specifically, I found that if any changes were made to the view after it was inflated that those changes would not get incorporated into the rendered bitmap.
我知道这可能是一个陈旧的问题,但是我在让这些解决方案中的任何一个对我有用时遇到了问题。具体来说,我发现如果在视图膨胀后对视图进行任何更改,这些更改将不会合并到渲染的位图中。
Here's the method which ended up working for my case. With one caveat, however. prior to calling getViewBitmap(View)
I inflated my view and asked it to layout with known dimensions. This was needed since my view layout would make it zero height/width until content was placed inside.
这是最终适用于我的案例的方法。但是,有一个警告。在打电话之前,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;
}
The "magic sauce" for me was found here: https://groups.google.com/forum/#!topic/android-developers/BxIBAOeTA1Q
在这里找到了我的“魔法酱”:https: //groups.google.com/forum/#!topic/android-developers/BxIBAOeTA1Q
Cheers,
干杯,
Levi
列维
回答by a.ch.
There is a great Kotlin extension function in Android KTX: View.drawToBitmap(Bitmap.Config)
Android KTX 中有一个很棒的 Kotlin 扩展功能: View.drawToBitmap(Bitmap.Config)
回答by Akhilesh Kumar
Hope this helps
希望这可以帮助
View view="some view instance";
view.setDrawingCacheEnabled(true);
Bitmap bitmap=view.getDrawingCache();
view.setDrawingCacheEnabled(false);
UpdategetDrawingCache()
method is deprecated in API level 28. So look for other alternative for API level > 28.
getDrawingCache()
API 级别 28 中不推荐使用更新方法。因此,请寻找 API 级别 > 28 的其他替代方法。
回答by android developer
I think this is a bit better :
我认为这更好一点:
/**
* 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;
}
Using the above code, you don't have to specify the size of the bitmap (use 0 for width&height) if you want to use the one of the view itself.
使用上面的代码,如果要使用视图本身之一,则不必指定位图的大小(宽度和高度使用 0)。
Also, if you wish to convert special views (SurfaceView, Surface or Window, for example) to a bitmap, you should consider using PixelCopyclass instead. It requires API 24 and above though. I don't know how to do it before.
此外,如果您希望将特殊视图(例如 SurfaceView、Surface 或 Window)转换为位图,您应该考虑使用PixelCopy类。不过它需要 API 24 及更高版本。我以前不知道怎么做。
回答by Shyam Kumar
Layout or view to bitmap:
布局或查看位图:
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;
}
Calling Method:
调用方式:
Bitmap src = createBitmapFromLayout(View.inflate(this, R.layout.sample, null)/* or pass your view object*/);
回答by Ashutosh Gupta
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);