Android View.getDrawingCache返回null,只有null。

101

能否有人向我解释一下为什么

public void addView(View child) {
  child.setDrawingCacheEnabled(true);
  child.setWillNotCacheDrawing(false);
  child.setWillNotDraw(false);
  child.buildDrawingCache();
  if(child.getDrawingCache() == null) { //TODO Make this work!
    Log.w("View", "View child's drawing cache is null");
  }
  setImageBitmap(child.getDrawingCache()); //TODO MAKE THIS WORK!!!
}

始终记录了绘图缓存为空,并将位图设置为空?

我是否必须在设置缓存之前实际绘制视图?

谢谢!


1
避免使用getDrawingCache(),而是使用View#drawCanvas的方法来截取整个视图的屏幕截图。 - Yuraj
10个回答

251

我也遇到了这个问题,并找到了以下答案:

v.setDrawingCacheEnabled(true);

// this is the important code :)  
// Without it the view will have a dimension of 0,0 and the bitmap will be null          
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); 

v.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false); // clear drawing cache

1
WebView的测量依赖于内容大小,因此如果网页尚未加载,则测量结果为0。尝试传递实际大小以代替UNSPECIFIED,例如MeasureSpec.makeMeasureSpec(800, MeasureSpec.EXACTLY)。 - Marcio Covre
3
即使使用MeasureSpec.EXACTLY,仍然返回null。 - user153275
在足够大的视图下,这对我不起作用(可能是因为我的手机内存资源非常有限)。下面cV2的答案对我很有效。 - Simon Forsberg
@nininho 如何在不使用getdrawingchache()方法的情况下从ImageView获取drawable? - Gorgeous_DroidVirus
在某些照片中返回 null。 - Jemshit Iskenderov
显示剩余8条评论

64

如果 getDrawingCache 总是返回 null,那么使用这个:

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(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
     v.draw(c);
     return b;
}

参考资料:https://dev59.com/iW025IYBdhLWcg3wAg7p#6272951


1
不错。这个对我有效,而其他的则没有。使用getLayoutParams中的值而不是v.getWidth()和v.getHeight()是否有任何原因? - Simon Forsberg
@cV2 好的,我明白了...这对我也有用...我解决了一些表面问题并清除了它...谢谢伙计... - Gorgeous_DroidVirus
4
我遇到了异常,提示宽度和高度必须大于0。以下是需要翻译的代码:private void takeScreenShot() { for (int i = 1; i < 4; i++) { View view = ScreenShotActivity.this.findViewById(R.id.relativelayout); Bitmap bitmap = loadBitmapFromView(view); } } - akash yadav
嘿,好久没用这段代码了,在这个例子中至少它能够按预期获取所有子视图,可能高度和宽度有问题?是0吗?祝好运。 - cV2
2
我认为“异常宽度和高度必须> 0”是由于您的“ImageView”尚未接收到图像,因此看起来为0。这会因不同人的代码而有所不同,但请确保在调用loadBitmapFromView()之后,您的ImageView确实包含图像。 - Azurespot
显示剩余7条评论

6

出现null的基本原因是视图没有确定尺寸。因此,使用view.getWidth()、view.getLayoutParams().width等方法,包括view.getDrawingCache()和view.buildDrawingCache()等方法都是无用的。

所以,您需要首先为视图设置尺寸,例如:

view.layout(0, 0, width, height);

(您已经根据自己的需求设置了“宽度”和“高度”,或者通过WindowManager等方式获取了它们。)

View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); root.setDrawingCacheEnabled(true); root.layout(0, 0, 480, 854); mBitmap = root.getDrawingCache(); - Narender Gusain

4

我使用这个替代。

myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Bitmap bitmap = Bitmap.createBitmap(myView.getDrawingCache());
        }
    });

3

最适合我的工作

    Bitmap bitmap = Bitmap.createBitmap( screen.getMeasuredWidth(), screen.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    screen.layout(0, 0, screen.getMeasuredWidth(), screen.getMeasuredHeight());
    screen.draw(canvas);

2
如果您想捕获的视图确实显示在屏幕上,但返回null,则表示您在Window manager生成它之前捕获了该视图。有些布局非常复杂。如果布局包含嵌套布局、layout_weight等,需要多次重新布局才能获取准确的大小。最好的解决方案是等待Window manager完成工作,然后获取屏幕截图。尝试在handler中放置getDrawingCache()。

1
我正在尝试根据视图动态创建n个图片。
LayoutInflater infalter=(LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View addview=infalter.inflate(R.layout.barcode_image_list_row_item, null);
final ImageView imv=(ImageView) addview.findViewById(R.id.imageView1);
final TextView tv=(TextView) addview.findViewById(R.id.textView1);

try {         
    final Bitmap bitmap = encodeAsBitmap(""+value, BarcodeFormat.CODE_128, 600, 300);

    if (bitmap != null) {
        // TODO Auto-generated method stub
        imv.setImageBitmap(bitmap);
        tv.setText(value);

        addview.setDrawingCacheEnabled(true);

        // this is the important code :)  
        // Without it the view will have a dimension of 0,0 and the bitmap will be null          
        addview.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        addview.layout(0, 0, addview.getMeasuredWidth(), addview.getMeasuredHeight()); 

        addview.buildDrawingCache(true);
        Bitmap b = Bitmap.createBitmap(addview.getDrawingCache());
        addview.setDrawingCacheEnabled(false); // clear drawing cache
        // saving the bitmap   
        savebarcode(b,value);
    }
} catch (WriterException e) {
    e.printStackTrace();
}

我认为这段代码会对某些人有所帮助。


1

@cV2和@nininho的答案对我都有效。

我发现另一个原因是我发现这个视图生成了一个宽度和高度为0的视图(例如,想象一下一个TextView有一个空字符串的文本)。在这种情况下,getDrawingCache将返回null,所以请确保检查。希望能帮助一些人。


1
错误可能是因为您的视图太大而无法适应绘图缓存。
我从我的日志中得到了关于“View.getDrawingCache返回null”的问题的解释:
W/View: View too large to fit into drawing cache, needs 19324704 bytes, only 16384000 available

Android文档也说道Android设备可能只有16MB的内存可供单个应用程序使用。这就是为什么你无法加载大位图的原因。


-1

这是获取位图的简单高效方法

public void addView(View v) {
        v.setDrawingCacheEnabled(true);
        v.buildDrawingCache();

        Bitmap bitmap = v.getDrawingCache();

        if(bitmap == null) {
            // bitmap is null
            // do whatever you want
        } else {
            setImageBitmap(bitmap);
        }
        v.setDrawingCacheEnabled(false);
        v.destroyDrawingCache();
    }

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