1

I am to create bitmap of a relative layout having a visible ImageView with two invisible TextViews and one invisible ImageView. But invisible views data was not shown in bitmap. If I set visible all those invisible views it is shown in bitmap, but not if hidden.

I am using below code -

 private Bitmap getBitmap(View v) {
    Bitmap bmp = null, b1 = null;
    RelativeLayout targetView = (RelativeLayout) v;
    targetView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
    targetView.buildDrawingCache();
    b1 = targetView.getDrawingCache();
    bmp = b1.copy(Bitmap.Config.ARGB_8888, true);
    targetView.destroyDrawingCache();
    return bmp;
}

I also used below link but that also didn't give me expected result.

Getting bitmap from a view visible-invisible

I am really in a fix.

Chirag Jain
  • 628
  • 11
  • 24

1 Answers1

2

The drawing cache saves a bitmap of what's currently drawn on screen. Naturally, this does not include hidden views.

The key difference between the article you provided in the link, and your code is that in the article, the bitmap cache is constructed for the invisible view.

However, you have a visible parent, which contains invisible views. When you create the drawing cache of the parent, the invisible views are, of course, not rendered.

In order for you invisible views to appear, you need to draw the views yourself in a bitmap, then draw that bitmap inside the bitmap which contins the parent.

Code sample:

//these fields should be initialized before using
TextView invisibleTextView1;

TextView invisibleTextView2;

ImageView invisibleImageView;

private Bitmap getBitmap(View v) {
    Bitmap bmp = null;
    Bitmap b1 = null;
    RelativeLayout targetView = (RelativeLayout) v;
    targetView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
    targetView.buildDrawingCache();
    b1 = targetView.getDrawingCache();
    bmp = b1.copy(Bitmap.Config.ARGB_8888, true);
    targetView.destroyDrawingCache();

    //create a canvas which will be used to draw the invisible views
    //inside the bitmap returned from the drawing cache
    Canvas fullCanvas = new Canvas(bmp);

    //create a list of invisible views
    List<View> invisibleViews = Arrays.asList(invisibleTextView1, invisibleImageView, invisibleTextView2);

    //iterate over the invisible views list
    for (View invisibleView : invisibleViews) {

        //create a bitmap the size of the current invisible view
        //in this bitmap the view will draw itself
        Bitmap invisibleViewBitmap = Bitmap.createBitmap(invisibleView.getWidth(), invisibleView.getHeight(), Bitmap.Config.ARGB_8888);

        //wrap the bitmap in a canvas. in this canvas the view will draw itself when calling "draw" 
        Canvas invisibleViewCanvas = new Canvas(invisibleViewBitmap);

        //instruct the invisible view to draw itself in the canvas we created
        invisibleView.draw(invisibleViewCanvas);

        //the view drew itself in the invisibleViewCanvas, which in term modified the invisibleViewBitmap
        //now, draw the invisibleViewBitmap in the fullCanvas, at the view's position
        fullCanvas.drawBitmap(invisibleViewBitmap, invisibleView.getLeft(), invisibleView.getTop(), null);

        //finally recycle the invisibleViewBitmap
        invisibleViewBitmap.recycle();
    }

    return bmp;
}

Final mentions:

  • if your invisible views have visibility = View.GONE, you should layout(...) on each one, before calling draw(...) in the loop.
  • if the parent view of your invisible views does not occupy the whole screen, then your invisible views will not be drawn at the correct position, since getLeft() & getTop() return the left & top properties in pixels, relative to the parent location. If your invisible views are within a parent which only covers part of the screen, then use instead:

    fullCanvas.drawBitmap(invisibleViewBitmap, invisibleView.getLeft() + parent.getLeft(), v.getTop() + v.getTop(), null);

Let me know if this works!

cjurjiu
  • 1,758
  • 13
  • 21
  • Thanks a lot for your quick reply. – Chirag Jain Aug 31 '17 at 06:33
  • Please check these images that what I required and getting with visible views and result with your updated code. I think it needs more calculations for layout size and position. Required: https://mega.nz/#!Tk5yiIgC!-jGvt07yDEJ65k19sYqivPgKBg600sZwrcJRKRmwa_s Result: https://mega.nz/#!vkwBCKhI!7RcSacv8whq-vMs48FNnoDKoKWVUt1ZctETM2fVn6YE – Chirag Jain Aug 31 '17 at 06:39
  • I had a call to `view.layout(...)` in the for loop, in a previous version of the answer. that call to `view.layout(...)` was unnecessary if your views are *Invisible* instead of *Gone*, and besides, it had the wrong params. Did you use the current version of the code I provided, or the one with the call to `layout`? just to know how to continue – cjurjiu Aug 31 '17 at 06:46
  • also, when you say your views are "hidden", do you mean View.INVISIBLE or View.GONE? I'm asking because views in View.INVISIBLE will still be laid out by the parent view, whereas those in View.GONE will not by default, and you will have to call `measure(...)` & `layout(...)` yourself, before calling `draw(..)` – cjurjiu Aug 31 '17 at 06:49
  • I am using View.INVISIBLE – Chirag Jain Aug 31 '17 at 06:52
  • I used that one by removing that layout line in loop which gives result as - https://mega.nz/#!fwAERDjQ!y5T7sxZVkHIEUyqP-Js103H0B5EOInVA8nMqPc02hMQ – Chirag Jain Aug 31 '17 at 06:54
  • alright, i understand what what the issue with my solution. the problem was that the invisible views shouldn't have been drawn in the full canvas, but in a canvas of their size. then, the backing bitmap of their size should have been drawn on the full canvas, at the view's position on screen. – cjurjiu Aug 31 '17 at 11:46
  • i have updated the answer & the suggested solution. can you please test? i have also tested this new approach myself and on my test project, it works – cjurjiu Aug 31 '17 at 11:46
  • Thanks a lot buddy due to some reason I could not respond earlier. It really worked. – Chirag Jain Sep 04 '17 at 11:41