AppWidget image with rounded corners

2019-03-04 04:37发布

问题:

So, I am dynamically creating an image within my app by animating various Views that I display to the user in the main layout of my application.

Currently I am generating my scene within a RelativeLayout, taking the image of the layout as a bitmap, then saving the bitmap to SD to be accessed by the appwidget via uri.

This is all working great, but... in an attmept to create rounded corners for the appwidget image, i've tried using these two snippets that I found here.

My Problem:

is that this method generates a drawable (whose rounded corners look perfect if displayed as a drawable) but I need to export these transparent corners as an image file. The drawToBitmap method in CustomView below, does generate a bitmap image, but the corners are full and square.

/**
 * shows a bitmap as if it had rounded corners. based on :
 * http://rahulswackyworld.blogspot.co.il/2013/04/android-drawables-with-rounded_7.html
 */
public class RoundedCornersDrawable extends BitmapDrawable {

    private final BitmapShader bitmapShader;
    private final Paint p;
    private final RectF rect;
    private final float borderRadius;

    public RoundedCornersDrawable(final Resources resources, final Bitmap bitmap, final float     borderRadius) {
        super(resources, bitmap);
        bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP,     Shader.TileMode.CLAMP);
        final Bitmap b = getBitmap();
        p = getPaint();
        p.setAntiAlias(true);
        p.setShader(bitmapShader);
        final int w = b.getWidth(), h = b.getHeight();
        rect = new RectF(0, 0, w, h);
        this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
    }

    @Override
    public void draw(final Canvas canvas) {
        canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
    }
}

and

public class CustomView extends ImageView {
    private FrameLayout mMainContainer;
    private boolean mIsDirty=false;

    // TODO for each change of views/content, set mIsDirty to true and call invalidate

    @Override
    protected void onDraw(final Canvas canvas) {
        if (mIsDirty) {
            mIsDirty = false;
            drawContent();
            return;
        }
        super.onDraw(canvas);
    }

    /**
     * draws the view's content to a bitmap. code based on :
     * http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
     */
    public static Bitmap drawToBitmap(final View viewToDrawFrom, final int width, final int height) {
        // Create a new bitmap and a new canvas using that bitmap
        final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(bmp);
        viewToDrawFrom.setDrawingCacheEnabled(true);
        // Supply measurements
        viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(),     MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(canvas.getHeight(), MeasureSpec.EXACTLY));
        // Apply the measures so the layout would resize before drawing.
        viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(),    viewToDrawFrom.getMeasuredHeight());
        // and now the bmp object will actually contain the requested layout
        canvas.drawBitmap(viewToDrawFrom.getDrawingCache(), 0, 0, new Paint());
        return bmp;
     }

    private void drawContent() {
        if (getMeasuredWidth() <= 0 || getMeasuredHeight() <= 0)
            return;
        final Bitmap bitmap = drawToBitmap(mMainContainer, getMeasuredWidth(), getMeasuredHeight());
        final RoundedCornersDrawable drawable = new RoundedCornersDrawable(getResources(),     bitmap, 15);
        setImageDrawable(drawable);
    }
}

I understand that a bitmap doesn't carry the alpha information that is needed to have transparent rounded corners in the image, So I tried saving the file as PNG like so;

RCD_test is a RoundedCornersDrawable

Bitmap bitmap = RCD_test.getBitmap();
bitmap.setHasAlpha(true);
OutputStream stream = new          
FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/test/screenshottest.png");
bitmap.compress(CompressFormat.PNG, 100, stream);
stream.close();

but to no avail. This whole approach may seem convoluded, but this is what I've come up with to address the constraints of AppWidget's RemoteViews.

My Question:

How can I take this RoundedCornersDrawable, and export it as a PNG file that properly depicts it's beautiful trasnparent corners?

thanks in advance for the help, and I'm open to any and all suggestions on different approaches to the problem as a whole!

回答1:

Sadly, AppWidgets are quite limited in terms of views. you can only use the views that Android supports.

The reason is that the code of the view needs to run on the container of the AppWidget, and that's a security risk, since you could get a glimpse at the private data of the app that shows it. So what Google did is that you need to prepare what to show, and when you finished, tell a restricted API how to show the AppWidget.

So the solution would be to flush the image as it should be shown , to an imageView or something similar. I suggest to do it in the background if it has a lot to prepare.

It all depends on your needs.



回答2:

In addition to this issue:

'It turns out that the size of my AppWidget was clipping the image the whole time. Clipping it just enough to remove the rounded corners, and just so little as to not have been obviously clipped. So for anyone that comes across this question... all of these method's work for this purpose (just don't forget to make your AppWidget big enough to see the results).'

Answer:

I found it was critical to also pass the RoundedCornersDrawable through the CustomView.drawToBitMap() method before exporting it to the PNG file.

I hope this all helps someone down the road someday!