9

THE PROBLEM

I'm try to save a view group (which has a CardView as one of its childern) as a PNG file. To achieve this,

  1. I inflate the view group and populate the views with required information
  2. Load an image to an image view via Glide
  3. Add a ViewTreeObserver.OnGlobalLayoutListener to the ViewTreeObserver of the image view and pass the entire (parent) view that is going to be shared to a method that converts the view to a bitmap when image view's bottom is greater than zero (image view's height attribute is set to wrap_content, thus its bottom will be zero until image is loaded).

By doing this, I'm able to convert the view to a bitmap, however, with one caveat: the CardView's show is not rendered on the bitmap.

FAILED ATTEMPTS

So far I've tried:

  1. Switching between layerType attribute from "software" to "hardware".
  2. Setting on and off cardUseCompatPadding attribute of the CardView.
  3. Tried setting the image drawable without using Glide.
  4. Tried without loading an image drawable at all.

THE CODE

Here are code snippets that might help you guys identify the problem:

The method used to convert a view to a bitmap

public static Bitmap getBitmapFromView(View view) {
    //Define a bitmap with the same size as the view
    Bitmap b = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
    //Bind a canvas to it
    Canvas canvas = new Canvas(b);
    //Get the view's background
    Drawable bgDrawable = view.getBackground();
    if (bgDrawable != null)
        //has background drawable, then draw it on the canvas
        bgDrawable.draw(canvas);
    else
        //does not have background drawable, then draw white background on the canvas
        canvas.drawColor(Color.WHITE);
    // draw the view on the canvas
    view.draw(canvas);
    //return the bitmap
    return b;
}

XML layout file of the view that's being inflated and passed to the getBitmapFromView() above.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="16dp">

    <com.devspark.robototextview.widget.RobotoTextView
        android:id="@+id/title"
        style="@style/text_subhead"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:layout_marginBottom="@dimen/lessons_horizontal_margin_narrow"
        android:layout_marginLeft="@dimen/lessons_horizontal_margin_narrow"
        android:layout_marginRight="@dimen/lessons_horizontal_margin_narrow"
        android:layout_marginTop="@dimen/lessons_horizontal_margin_narrow"
        android:gravity="left"
        app:typeface="roboto_medium" />

    <com.devspark.robototextview.widget.RobotoTextView
        android:id="@+id/text"
        style="@style/text_subhead"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/lessons_horizontal_margin_narrow"
        android:layout_marginRight="@dimen/lessons_horizontal_margin_narrow"
        android:gravity="left"
        android:textColor="@color/text"
        app:typeface="roboto_regular" />

    <android.support.v7.widget.CardView
        android:id="@+id/image_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/lessons_horizontal_margin_narrow"
        app:cardCornerRadius="@dimen/lessons_image_card_corner_radius"
        app:cardElevation="3dp"
        app:cardPreventCornerOverlap="false"
        app:cardUseCompatPadding="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <com.makeramen.roundedimageview.RoundedImageView
                android:id="@+id/image"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:contentDescription="@null"
                app:riv_corner_radius_top_left="@dimen/lessons_image_card_corner_radius"
                app:riv_corner_radius_top_right="@dimen/lessons_image_card_corner_radius" />

            <com.devspark.robototextview.widget.RobotoTextView
                android:id="@+id/caption"
                style="@style/text_caption"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/lessons_image_card_caption_margin"
                android:gravity="left"
                app:typeface="roboto_condensed_regular" />

        </LinearLayout>

    </android.support.v7.widget.CardView>

    <!-- Some other views that aren't particularly interesting -->

</LinearLayout>
fahmy
  • 3,543
  • 31
  • 47
  • Not sure if relevant but maybe you could try setting a small `android:padding`, and `android:clipToPadding="false"` for the cardview? – headuck Oct 04 '15 at 09:11
  • Pretty sure its not related to the padding of the parent view or the card view. The shadow renders on screen without any problem and enough room is given to ensure that. Thanks though. – fahmy Oct 04 '15 at 09:20
  • I face the same problem, though I'm more interested in getting the rounded corners drawn to my canvas. Neither rounded corners, nor shadow gets drawn. I also use view.draw(canvas) – arberg Feb 19 '16 at 13:58
  • Same here. Any update on this issue ? – galex Mar 06 '17 at 12:51
  • @galex nope, none :( – fahmy Mar 08 '17 at 16:08
  • @fahmy seems like shadows are not drawn on views only by calling measure and layout, which is really weird... – galex Mar 09 '17 at 10:19
  • Having the same exact issue. Anyone having any success with this? – sheitan Oct 25 '17 at 07:33
  • I've had no luck whatsoever. Not even with the answer provided below. No shadow or round corners. Has someone done any progress at all? – Miguel Lasa Jun 23 '19 at 00:17

3 Answers3

4

just change cardview to view, and set

android:background="@android:drawable/dialog_holo_light_frame"

ofcause you need to deal the padding yourself

lynn
  • 41
  • 3
2

As @galex said - shadows are not drawn on views only by calling measure and layout.

So we can't use the elevation. Also we can't use the drawable shadow, because then we get sharp angles and straight sides.

Solution: use the png 9-path resizable drawable. For this we can use this beautiful tool: Android shadow generator

  1. Create 9-path files for all of mdpi, hdpi, xhdpi, xxhdpi and xxxhdpi.
  2. Put all of your png`s to res/drawables folder.
  3. Now we can use this drawable like background for view where we want to see shadow.

Note that for different densities, you must change following parameter: height and width of the view, shadow offsets (x and y), blur, round corners radius and paddings.

Multipliers for diffrent densities:

LDPI - x0.75//practically not used, so you can do without it
MDPI - x1.0// means original size 
HDPI - x1.5
XHDPI - x2.0
XXHDPI - x3.0
XXXHDPI - x4.0

For example if you need to create rectangle with 30dp x 100dp and radius = 8dp

list of 9.path images you should generate:

  1. 30х100px, rad = 8
  2. 45х150px, rad = 12
  3. 60х200px, rad = 16
  4. 90х300px, rad = 24
  5. 120х400px, rad = 32
tasjapr
  • 632
  • 4
  • 13
0

I have a same problem. So after searching, I founded this. Hope this help https://medium.com/@ArmanSo/take-control-of-views-shadow-android-c6b35ba573e9

  • Please also provide all the relevant info in your answer. See here: https://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers, why link-only answers do not fit the format of stack-overflow. – NOhs Jul 26 '19 at 16:43