redstonedev
redstonedev

Reputation: 119

use blurview as relative view

I'm currently using a BluringView XML Object as gotten from the BlurringView.java file (https://github.com/500px/500px-android-blur). It's basically just a custom view that blurs a sibling view that's beneath it. The problem I'm having is that I can't populate the BlurringView with other objects. Here's the code:

package com.fivehundredpx.android.blur;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import android.util.AttributeSet;
import android.view.View;

/**
 * A custom view for presenting a dynamically blurred version of another view's content.
 * <p/>
 * Use {@link #setBlurredView(android.view.View)} to set up the reference to the view to be blurred.
 * After that, call {@link #invalidate()} to trigger blurring whenever necessary.
 */
public class BlurringView extends View {

public BlurringView(Context context) {
    this(context, null);
}

public BlurringView(Context context, AttributeSet attrs) {
    super(context, attrs);

    final Resources res = getResources();
    final int defaultBlurRadius = res.getInteger(R.integer.default_blur_radius);
    final int defaultDownsampleFactor = res.getInteger(R.integer.default_downsample_factor);
    final int defaultOverlayColor = res.getColor(R.color.default_overlay_color);

    initializeRenderScript(context);

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PxBlurringView);
    setBlurRadius(a.getInt(R.styleable.PxBlurringView_blurRadius, defaultBlurRadius));
    setDownsampleFactor(a.getInt(R.styleable.PxBlurringView_downsampleFactor,
            defaultDownsampleFactor));
    setOverlayColor(a.getColor(R.styleable.PxBlurringView_overlayColor, defaultOverlayColor));
    a.recycle();
}

public void setBlurredView(View blurredView) {
    mBlurredView = blurredView;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mBlurredView != null) {
        if (prepare()) {
            // If the background of the blurred view is a color drawable, we use it to clear
            // the blurring canvas, which ensures that edges of the child views are blurred
            // as well; otherwise we clear the blurring canvas with a transparent color.
            if (mBlurredView.getBackground() != null && mBlurredView.getBackground() instanceof ColorDrawable){
                mBitmapToBlur.eraseColor(((ColorDrawable) mBlurredView.getBackground()).getColor());
            }else {
                mBitmapToBlur.eraseColor(Color.TRANSPARENT);
            }

            mBlurredView.draw(mBlurringCanvas);
            blur();

            canvas.save();
            canvas.translate(mBlurredView.getX() - getX(), mBlurredView.getY() - getY());
            canvas.scale(mDownsampleFactor, mDownsampleFactor);
            canvas.drawBitmap(mBlurredBitmap, 0, 0, null);
            canvas.restore();
        }
        canvas.drawColor(mOverlayColor);
    }
}

public void setBlurRadius(int radius) {
    mBlurScript.setRadius(radius);
}

public void setDownsampleFactor(int factor) {
    if (factor <= 0) {
        throw new IllegalArgumentException("Downsample factor must be greater than 0.");
    }

    if (mDownsampleFactor != factor) {
        mDownsampleFactor = factor;
        mDownsampleFactorChanged = true;
    }
}

public void setOverlayColor(int color) {
    mOverlayColor = color;
}

private void initializeRenderScript(Context context) {
    mRenderScript = RenderScript.create(context);
    mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
}

protected boolean prepare() {
    final int width = mBlurredView.getWidth();
    final int height = mBlurredView.getHeight();

    if (mBlurringCanvas == null || mDownsampleFactorChanged
            || mBlurredViewWidth != width || mBlurredViewHeight != height) {
        mDownsampleFactorChanged = false;

        mBlurredViewWidth = width;
        mBlurredViewHeight = height;

        int scaledWidth = width / mDownsampleFactor;
        int scaledHeight = height / mDownsampleFactor;

        // The following manipulation is to avoid some RenderScript artifacts at the edge.
        scaledWidth = scaledWidth - scaledWidth % 4 + 4;
        scaledHeight = scaledHeight - scaledHeight % 4 + 4;

        if (mBlurredBitmap == null
                || mBlurredBitmap.getWidth() != scaledWidth
                || mBlurredBitmap.getHeight() != scaledHeight) {
            mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight,
                    Bitmap.Config.ARGB_8888);
            if (mBitmapToBlur == null) {
                return false;
            }

            mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight,
                    Bitmap.Config.ARGB_8888);
            if (mBlurredBitmap == null) {
                return false;
            }
        }

        mBlurringCanvas = new Canvas(mBitmapToBlur);
        mBlurringCanvas.scale(1f / mDownsampleFactor, 1f / mDownsampleFactor);
        mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur,
                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
        mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType());
    }
    return true;
}

protected void blur() {
    mBlurInput.copyFrom(mBitmapToBlur);
    mBlurScript.setInput(mBlurInput);
    mBlurScript.forEach(mBlurOutput);
    mBlurOutput.copyTo(mBlurredBitmap);
}

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    if (mRenderScript != null){
        mRenderScript.destroy();
    }
}

private int mDownsampleFactor;
private int mOverlayColor;

private View mBlurredView;
private int mBlurredViewWidth, mBlurredViewHeight;

private boolean mDownsampleFactorChanged;
private Bitmap mBitmapToBlur, mBlurredBitmap;
private Canvas mBlurringCanvas;
private RenderScript mRenderScript;
private ScriptIntrinsicBlur mBlurScript;
private Allocation mBlurInput, mBlurOutput;

}

Is there any way to modify the BlurringView.java class so the BlurringView xml object can be used like a RelativeView or something similar? I want to be able to have the BlurringView be the parent to other objects.

I need this, because I'm using the BlurringView together with a SlidingUpPanelLayout (https://github.com/umano/AndroidSlidingUpPanel) and the SlidingUpPanelLayout only allows two children for it to function. Thus I can't just overlay items over the BlurringView. I need the BlurringView to be their parent.

Please let me know if you need clarification.

-R

Upvotes: 1

Views: 783

Answers (1)

redstonedev
redstonedev

Reputation: 119

Blockquote Did you try to do an extract method of your constructor, implement the same methon in each of the three default constructors and extend from RelativeLayout?

The RelativeLayout actually have a onDraw method, maybe isn't being called because you didn't invoke the method setWillNotDraw(false), try using that method to trigger the onDraw or use an invalidate() at the end of the constructors.

@astinx answered this question.

All I had to do was change the BlurringView class to extend a RelativeLayout instead of a View. I then called the setWillNotDraw(false) method as well as the invalidate() method in the constructor and now I'm able to populate the BlurringView with children! Magic.

-R

Upvotes: 2

Related Questions