101

Would anyone please try to explain to me why

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!!!
}

ALWAYS logs that the drawing cache is null, and sets the bitmap to null?

Do I have to actually draw the view before the cache is set?

Thanks!

Bryan Herbst
  • 66,602
  • 10
  • 133
  • 120
Bex
  • 2,905
  • 2
  • 33
  • 36
  • 1
    http://stackoverflow.com/questions/9791714/take-a-screenshot-of-a-whole-view#comment67696694_31775271 avoid using `getDrawingCache()` use `View#draw` to `Canvas` approach – Yuraj Oct 24 '16 at 11:02

10 Answers10

251

I was having this problem also and found this answer:

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
Marcio Covre
  • 4,556
  • 2
  • 22
  • 24
  • 1
    WebView measurement depends on the content size, so if the web page is not loaded yet you will get a measure of 0. Try passing the real size to measure instead of UNSPECIFIED like MeasureSpec.makeMeasureSpec(800, MeasureSpec.EXACTLY); – Marcio Covre Nov 01 '12 at 11:59
  • 3
    Still returns null even with MeasureSpec.EXACTLY. –  Jan 21 '13 at 06:29
  • On a big enough view, this did not work for me. (Possibly because I have a phone with very limited memory resources). The answer below by cV2 worked fine for me. – Simon Forsberg Jul 23 '13 at 23:16
  • @nininho how to get drawable from imageview without using the getdrawingchache() method? – Gorgeous_DroidVirus Mar 19 '14 at 12:30
  • It works well. But it affects in UI. Please help to solve this issue. – Vivek Ravi Mar 28 '14 at 07:31
  • @nininho i got the drawing on images, but i need to get the getdrawingcache on running surfaceview.. then what can i do next? – Gorgeous_DroidVirus Jun 02 '14 at 10:30
  • If you are not doing something intensive with the surfaceview you could try to set the view Layer Type to software (http://developer.android.com/reference/android/view/View.html#LAYER_TYPE_SOFTWARE), this way you're rendering to a bitmap and the show on screen, and getdrawingcache should work. – Marcio Covre Jun 02 '14 at 11:50
  • @nininho thanks for "v.setDrawingCacheEnabled(false);" +1 for it – Bhavin Chauhan Jul 21 '14 at 09:11
  • Fire exception "COULD NO CAPTURE SCREENSHOTjava.lang.IllegalStateException: ActionBarView can only be used with android:layout_width="match_parent" (or fill_parent)" – Krunal Indrodiya May 06 '15 at 10:04
  • returns null in some photo – Jemshit Feb 03 '16 at 08:44
  • @MarcioCovre using above code I am getting bitmap width as screensize where view size is greater then screen size can you please help me to solve it ? – PriyankaChauhan Nov 02 '16 at 10:59
  • @pcpriyanka with MeasureSpec.UNSPECIFIED I think it is always limited to screen size, but if you know the real size you can use MeasureSpec.EXACTLY and pass the size instead of 0 on measure() – Marcio Covre Nov 04 '16 at 11:01
  • @MarcioCovre If I save the bitmap with EXACTLY size then is stretch the image or bitmap – PriyankaChauhan Nov 04 '16 at 11:04
63

if getDrawingCache is always returning null guys: use this:

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;
}

Reference: https://stackoverflow.com/a/6272951/371749

Community
  • 1
  • 1
cV2
  • 5,229
  • 3
  • 43
  • 53
  • 1
    Good one. This one worked for me while the others did not. Is there any reason to use the values from `getLayoutParams` instead of v.getWidth() and v.getHeight()? – Simon Forsberg Jul 23 '13 at 23:14
  • sorry, personally, can't help you with your question :'( -> nice that it worked :) – cV2 Jul 26 '13 at 11:36
  • @cV2 i got the drawing on images, but i need to get the getdrawingcache on running surfaceview.. then what can i do next? – Gorgeous_DroidVirus Jun 02 '14 at 10:29
  • hey @Android_Virus, for me this code was also working on surfaceview... possible that something else is wrong? – cV2 Jun 02 '14 at 23:11
  • @cV2 yup got it... also working for me... i solve some issue in surface and clear it.. thanks dude... – Gorgeous_DroidVirus Jun 03 '14 at 04:16
  • 4
    i am getting exception width and height must be >0..............................private void takeScreenShot() { for (int i = 1; i < 4; i++) { //startDialog(); View view = ScreenShotActivity.this.findViewById(R.id.relativelayout); Bitmap bitmap = loadBitmapFromView(view);}} – akash yadav Sep 11 '14 at 10:35
  • @cV2 I am passing linear layout. but its not getting child views. What to do in this case. – Shabbir Dhangot Mar 02 '15 at 10:42
  • hey long-time-not-used this code, in the example at least it did work and got all child views, as intended, possibly height and width is wrong? 0 possibly? good luck – cV2 Mar 03 '15 at 14:19
  • 2
    I think the ` exception width and height must be >0` comes about when your `ImageView` has not received an image yet, so it appears to be 0. This would play out differently for different people's code, but make sure your call to `loadBitmapFromView()` is definitely after your `ImageView` contains an image. – Azurespot Apr 02 '15 at 07:05
  • thanks for your answer,and i tried this code for after zooming the image but resultant bitmap has very bad quality. how to get resultant bitmap with good quality. – user512 Jan 08 '16 at 09:55
  • `java.lang.IllegalArgumentException: width and height must be > 0 at android.graphics.Bitmap.createBitmap`, in my case because a fragment has not been already drawn even in onResume. – CoolMind Aug 17 '16 at 11:42
  • Thanks. I have to comment out `v.layout(...`, as it will affect the view on my screen. – Cheok Yan Cheng Aug 02 '18 at 16:54
6

The basic reason one gets nulls is that the view is not dimentioned. All attempts then, using view.getWidth(), view.getLayoutParams().width, etc., including view.getDrawingCache() and view.buildDrawingCache(), are useless. So, you need first to set dimensions to the view, e.g.:

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

(You have already set 'width' and 'height' as you like or obtained them with WindowManager, etc.)

Apostolos
  • 3,115
  • 25
  • 28
  • View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); root.setDrawingCacheEnabled(true); root.layout(0, 0, 480, 854); mBitmap = root.getDrawingCache(); – Narender Gusain Mar 01 '17 at 10:01
4

Im using this instead.

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

Work best 4me

    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);
Alexey Kurilov
  • 438
  • 4
  • 10
2

If the view you want catch really shows on screen, but it return null. That means you catch the view before Window manager generate it. Some layouts are very complicated. If layout includes nested layouts, layout_weight..etc, it causes several times relayout to get exactly size. The best solution is waiting until window manager finish job and then get screen shot. Try to put getDrawingCache() in handler.

Kislingk
  • 1,427
  • 14
  • 23
1

@cV2 and @nininho's answers both work for me.

One of the other reasons that i found out the hard way was that the view that i had was generating a view that has width and height of 0 (i.e. imagine having a TextView with a string text of an empty string). In this case, getDrawingCache will return null, so just be sure to check for that. Hope that helps some people out there.

Bundeeteddee
  • 724
  • 11
  • 19
1

I am trying to creating the n number of images dynamically based on view.

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();
}

I think this code will help someone..

Bex
  • 2,905
  • 2
  • 33
  • 36
Harish
  • 237
  • 2
  • 10
1

The error may be bacause your View too large to fit into drawing cache.

I got the explanation of my "View.getDrawingCache returns null" problem from my logs:

W/View: View too large to fit into drawing cache, needs 19324704 bytes, only 16384000 available

Android docs also says: Android devices can have as little as 16MB of memory available to a single application. That is why you can not load big bitmap.

Yuliia Ashomok
  • 8,336
  • 2
  • 60
  • 69
-1

This the simple and efficient way to get bitmap

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();
    }
Jemshit
  • 9,501
  • 5
  • 69
  • 106
Nilesh B
  • 937
  • 1
  • 9
  • 14