Android Blur View (Blur background behind the view)

后端 未结 4 588
暖寄归人
暖寄归人 2020-12-24 15:10

I am trying to make the bottom part of an Image blur for the view on top it like in the image.

I tried blurring it using Rendenscript but I am not able to blur only

相关标签:
4条回答
  • 2020-12-24 15:50

    The following code will blur out left and right sides of image using the following:

    Inside ViewPictureActivity:

    private void applyBlur(final ImageView image) {
        image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                image.getViewTreeObserver().removeOnPreDrawListener(this);
                image.buildDrawingCache();
    
                Bitmap bmp = image.getDrawingCache();
                blur(bmp, image);
                return true;
            }
        });
    }
    
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private void blur(Bitmap bkg, View view) {
    
        float radius = 20;
    
        Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth()),
                (int) (view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
    
        Canvas canvas = new Canvas(overlay);
        canvas.translate(-view.getLeft(), -view.getTop());
        canvas.drawBitmap(bkg, 100, 0,null);
        canvas.drawBitmap(bkg, -95,0,null);
        RenderScript rs = RenderScript.create(getApplicationContext());
    
        Allocation overlayAlloc = Allocation.createFromBitmap(
                rs, overlay);
    
        ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
                rs, overlayAlloc.getElement());
    
        blur.setInput(overlayAlloc);
    
        blur.setRadius(radius);
    
        blur.forEach(overlayAlloc);
    
        overlayAlloc.copyTo(overlay);
    
        view.setBackground(new BitmapDrawable(
                getResources(), overlay));
    
        rs.destroy();
    }//end blur
    

    Add this class to your project:

    public class ZoomableImageView extends android.support.v7.widget.AppCompatImageView
    {
        Matrix matrix = new Matrix();
    
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    static final int CLICK = 3;
    int mode = NONE;
    
    PointF last = new PointF();
    PointF start = new PointF();
    float minScale = 1f;
    float maxScale = 4f;
    float[] m;
    
    float redundantXSpace, redundantYSpace;
    float width, height;
    float saveScale = 1f;
    float right, bottom, origWidth, origHeight, bmWidth, bmHeight;
    
    ScaleGestureDetector mScaleDetector;
    Context context;
    
    public ZoomableImageView(Context context, AttributeSet attr)
    {
        super(context, attr);
        super.setClickable(true);
        this.context = context;
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        matrix.setTranslate(1f, 1f);
        m = new float[9];
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);
    
        setOnTouchListener(new OnTouchListener()
        {
    
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                mScaleDetector.onTouchEvent(event);
    
                matrix.getValues(m);
                float x = m[Matrix.MTRANS_X];
                float y = m[Matrix.MTRANS_Y];
                PointF curr = new PointF(event.getX(), event.getY());
    
                switch (event.getAction())
                {
                    //when one finger is touching
                    //set the mode to DRAG
                    case MotionEvent.ACTION_DOWN:
                        last.set(event.getX(), event.getY());
                        start.set(last);
                        mode = DRAG;
                        break;
                    //when two fingers are touching
                    //set the mode to ZOOM
                    case MotionEvent.ACTION_POINTER_DOWN:
                        last.set(event.getX(), event.getY());
                        start.set(last);
                        mode = ZOOM;
                        break;
                    //when a finger moves
                    //If mode is applicable move image
                    case MotionEvent.ACTION_MOVE:
                        //if the mode is ZOOM or
                        //if the mode is DRAG and already zoomed
                        if (mode == ZOOM || (mode == DRAG && saveScale > minScale))
                        {
                            float deltaX = curr.x - last.x;// x difference
                            float deltaY = curr.y - last.y;// y difference
                            float scaleWidth = Math.round(origWidth * saveScale);// width after applying current scale
                            float scaleHeight = Math.round(origHeight * saveScale);// height after applying current scale
                            //if scaleWidth is smaller than the views width
                            //in other words if the image width fits in the view
                            //limit left and right movement
                            if (scaleWidth < width)
                            {
                                deltaX = 0;
                                if (y + deltaY > 0)
                                    deltaY = -y;
                                else if (y + deltaY < -bottom)
                                    deltaY = -(y + bottom);
                            }
                            //if scaleHeight is smaller than the views height
                            //in other words if the image height fits in the view
                            //limit up and down movement
                            else if (scaleHeight < height)
                            {
                                deltaY = 0;
                                if (x + deltaX > 0)
                                    deltaX = -x;
                                else if (x + deltaX < -right)
                                    deltaX = -(x + right);
                            }
                            //if the image doesnt fit in the width or height
                            //limit both up and down and left and right
                            else
                            {
                                if (x + deltaX > 0)
                                    deltaX = -x;
                                else if (x + deltaX < -right)
                                    deltaX = -(x + right);
    
                                if (y + deltaY > 0)
                                    deltaY = -y;
                                else if (y + deltaY < -bottom)
                                    deltaY = -(y + bottom);
                            }
                            //move the image with the matrix
                            matrix.postTranslate(deltaX, deltaY);
                            //set the last touch location to the current
                            last.set(curr.x, curr.y);
                        }
                        break;
                    //first finger is lifted
                    case MotionEvent.ACTION_UP:
                        mode = NONE;
                        int xDiff = (int) Math.abs(curr.x - start.x);
                        int yDiff = (int) Math.abs(curr.y - start.y);
                        if (xDiff < CLICK && yDiff < CLICK)
                            performClick();
                        break;
                    // second finger is lifted
                    case MotionEvent.ACTION_POINTER_UP:
                        mode = NONE;
                        break;
                }
                setImageMatrix(matrix);
                invalidate();
                return true;
            }
    
        });
    }
    
    @Override
    public void setImageBitmap(Bitmap bm)
    {
        super.setImageBitmap(bm);
        bmWidth = bm.getWidth();
        bmHeight = bm.getHeight();
    }
    
    public void setMaxZoom(float x)
    {
        maxScale = x;
    }
    
    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
    {
    
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector)
        {
            mode = ZOOM;
            return true;
        }
    
        @Override
        public boolean onScale(ScaleGestureDetector detector)
        {
            float mScaleFactor = detector.getScaleFactor();
            float origScale = saveScale;
            saveScale *= mScaleFactor;
            if (saveScale > maxScale)
            {
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            }
            else if (saveScale < minScale)
            {
                saveScale = minScale;
                mScaleFactor = minScale / origScale;
            }
            right = width * saveScale - width - (2 * redundantXSpace * saveScale);
            bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
            if (origWidth * saveScale <= width || origHeight * saveScale <= height)
            {
                matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
                if (mScaleFactor < 1)
                {
                    matrix.getValues(m);
                    float x = m[Matrix.MTRANS_X];
                    float y = m[Matrix.MTRANS_Y];
                    if (mScaleFactor < 1)
                    {
                        if (Math.round(origWidth * saveScale) < width)
                        {
                            if (y < -bottom)
                                matrix.postTranslate(0, -(y + bottom));
                            else if (y > 0)
                                matrix.postTranslate(0, -y);
                        }
                        else
                        {
                            if (x < -right)
                                matrix.postTranslate(-(x + right), 0);
                            else if (x > 0)
                                matrix.postTranslate(-x, 0);
                        }
                    }
                }
            }
            else
            {
                matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
                matrix.getValues(m);
                float x = m[Matrix.MTRANS_X];
                float y = m[Matrix.MTRANS_Y];
                if (mScaleFactor < 1) {
                    if (x < -right)
                        matrix.postTranslate(-(x + right), 0);
                    else if (x > 0)
                        matrix.postTranslate(-x, 0);
                    if (y < -bottom)
                        matrix.postTranslate(0, -(y + bottom));
                    else if (y > 0)
                        matrix.postTranslate(0, -y);
                }
            }
            return true;
        }
    }
    
    @Override
    protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
        //Fit to screen.
        float scale;
        float scaleX =  width / bmWidth;
        float scaleY = height / bmHeight;
        scale = Math.min(scaleX, scaleY);
        matrix.setScale(scale, scale);
        setImageMatrix(matrix);
        saveScale = 1f;
    
        // Center the image
        redundantYSpace = height - (scale * bmHeight) ;
        redundantXSpace = width - (scale * bmWidth);
        redundantYSpace /= 2;
        redundantXSpace /= 2;
    
        matrix.postTranslate(redundantXSpace, redundantYSpace);
    
        origWidth = width - 2 * redundantXSpace;
        origHeight = height - 2 * redundantYSpace;
        right = width * saveScale - width - (2 * redundantXSpace * saveScale);
        bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
        setImageMatrix(matrix);
    }
    

    }

    I used the following layout to display the image:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.yourpackagename">
    
    <com.example.yourpackagename.ZoomableImageView
        android:id="@+id/zivImage"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

    Using the code in your ViewPictureActivity:

    ZoomableImageView zifImage = findViewById(R.id.zivImage);
     zifImage.setImageBitmap(HelperClass.clientImageBitmap);
            applyBlur(zifImage);
    

    Code used in this answer is taken from above answer and modified.

    Hope this helps.

    0 讨论(0)
  • 2020-12-24 15:54

    Add these two classes to your app,

    1> BlurKit.Java

    public class BlurKit {
    
        private static BlurKit instance;
    
        private RenderScript rs;
    
        public static void init(Context context) {
            if (instance != null) {
                return;
            }
    
            instance = new BlurKit();
            instance.rs = RenderScript.create(context);
        }
    
        public Bitmap blur(Bitmap src, int radius) {
            final Allocation input = Allocation.createFromBitmap(rs, src);
            final Allocation output = Allocation.createTyped(rs, input.getType());
            final ScriptIntrinsicBlur script;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
                script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
                script.setRadius(radius);
                script.setInput(input);
                script.forEach(output);
            }
            output.copyTo(src);
            return src;
        }
    
        public Bitmap blur(View src, int radius) {
            Bitmap bitmap = getBitmapForView(src, 1f);
            return blur(bitmap, radius);
        }
    
        public Bitmap fastBlur(View src, int radius, float downscaleFactor) {
            Bitmap bitmap = getBitmapForView(src, downscaleFactor);
            return blur(bitmap, radius);
        }
    
        private Bitmap getBitmapForView(View src, float downscaleFactor) {
            Bitmap bitmap = Bitmap.createBitmap(
                    (int) (src.getWidth() * downscaleFactor),
                    (int) (src.getHeight() * downscaleFactor),
                    Bitmap.Config.ARGB_4444
            );
    
            Canvas canvas = new Canvas(bitmap);
            Matrix matrix = new Matrix();
            matrix.preScale(downscaleFactor, downscaleFactor);
            canvas.setMatrix(matrix);
            src.draw(canvas);
    
            return bitmap;
        }
    
        public static BlurKit getInstance() {
            if (instance == null) {
                throw new RuntimeException("BlurKit not initialized!");
            }
    
            return instance;
        }
    
    }
    

    2> BlurLayout.Java

    public class BlurLayout extends FrameLayout {
    
        public static final float DEFAULT_DOWNSCALE_FACTOR = 0.12f;
        public static final int DEFAULT_BLUR_RADIUS = 12;
        public static final int DEFAULT_FPS = 60;
    
        // Customizable attributes
    
        /** Factor to scale the view bitmap with before blurring. */
        private float mDownscaleFactor;
    
        /** Blur radius passed directly to stackblur library. */
        private int mBlurRadius;
    
        /** Number of blur invalidations to do per second.  */
        private int mFPS;
    
        // Calculated class dependencies
    
        /** Reference to View for top-parent. For retrieval see {@link #getActivityView() getActivityView}. */
        private WeakReference<View> mActivityView;
    
        public BlurLayout(Context context) {
            super(context, null);
        }
    
        public BlurLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
            BlurKit.init(context);
    
            TypedArray a = context.getTheme().obtainStyledAttributes(
                    attrs,
                    R.styleable.BlurLayout,
                    0, 0);
    
            try {
                mDownscaleFactor = a.getFloat(R.styleable.BlurLayout_downscaleFactor, DEFAULT_DOWNSCALE_FACTOR);
                mBlurRadius = a.getInteger(R.styleable.BlurLayout_blurRadius, DEFAULT_BLUR_RADIUS);
                mFPS = a.getInteger(R.styleable.BlurLayout_fps, DEFAULT_FPS);
            } finally {
                a.recycle();
            }
    
            if (mFPS > 0) {
                Choreographer.getInstance().postFrameCallback(invalidationLoop);
            }
        }
    
        /** Choreographer callback that re-draws the blur and schedules another callback. */
        private Choreographer.FrameCallback invalidationLoop = new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                invalidate();
                Choreographer.getInstance().postFrameCallbackDelayed(this, 1000 / mFPS);
            }
        };
    
        /**
         * {@inheritDoc}
         */
        @Override
        public void invalidate() {
            super.invalidate();
            Bitmap bitmap = blur();
            if (bitmap != null) {
                setBackground(new BitmapDrawable(bitmap));
            }
        }
    
        /**
         * Recreates blur for content and sets it as the background.
         */
        private Bitmap blur() {
            if (getContext() == null) {
                return null;
            }
    
            // Check the reference to the parent view.
            // If not available, attempt to make it.
            if (mActivityView == null || mActivityView.get() == null) {
                mActivityView = new WeakReference<>(getActivityView());
                if (mActivityView.get() == null) {
                    return null;
                }
            }
    
            // Calculate the relative point to the parent view.
            Point pointRelativeToActivityView = getPositionInScreen();
    
            // Set alpha to 0 before creating the parent view bitmap.
            // The blur view shouldn't be visible in the created bitmap.
            setAlpha(0);
    
            // Screen sizes for bound checks
            int screenWidth = mActivityView.get().getWidth();
            int screenHeight = mActivityView.get().getHeight();
    
            // The final dimensions of the blurred bitmap.
            int width = (int) (getWidth() * mDownscaleFactor);
            int height = (int) (getHeight() * mDownscaleFactor);
    
            // The X/Y position of where to crop the bitmap.
            int x = (int) (pointRelativeToActivityView.x * mDownscaleFactor);
            int y = (int) (pointRelativeToActivityView.y * mDownscaleFactor);
    
            // Padding to add to crop pre-blur.
            // Blurring straight to edges has side-effects so padding is added.
            int xPadding = getWidth() / 8;
            int yPadding = getHeight() / 8;
    
            // Calculate padding independently for each side, checking edges.
            int leftOffset = -xPadding;
            leftOffset = x + leftOffset >= 0 ? leftOffset : 0;
    
            int rightOffset = xPadding;
            rightOffset = x + getWidth() + rightOffset <= screenWidth ? rightOffset : screenWidth - getWidth() - x;
    
            int topOffset = -yPadding;
            topOffset = y + topOffset >= 0 ? topOffset : 0;
    
            int bottomOffset = yPadding;
            bottomOffset = y + height + bottomOffset <= screenHeight ? bottomOffset : 0;
    
            // Create parent view bitmap, cropped to the BlurLayout area with above padding.
            Bitmap bitmap;
            try {
                bitmap = getDownscaledBitmapForView(
                        mActivityView.get(),
                        new Rect(
                                pointRelativeToActivityView.x + leftOffset,
                                pointRelativeToActivityView.y + topOffset,
                                pointRelativeToActivityView.x + getWidth() + Math.abs(leftOffset) + rightOffset,
                                pointRelativeToActivityView.y + getHeight() + Math.abs(topOffset) + bottomOffset
                        ),
                        mDownscaleFactor
                );
            } catch (NullPointerException e) {
                return null;
            }
    
            // Blur the bitmap.
            bitmap = BlurKit.getInstance().blur(bitmap, mBlurRadius);
    
            //Crop the bitmap again to remove the padding.
            bitmap = Bitmap.createBitmap(
                    bitmap,
                    (int) (Math.abs(leftOffset) * mDownscaleFactor),
                    (int) (Math.abs(topOffset) * mDownscaleFactor),
                    width,
                    height
            );
    
            // Make self visible again.
            setAlpha(1);
    
            // Set background as blurred bitmap.
            return bitmap;
        }
    
        /**
         * Casts context to Activity and attempts to create a view reference using the window decor view.
         * @return View reference for whole activity.
         */
        private View getActivityView() {
            Activity activity;
            try {
                activity = (Activity) getContext();
            } catch (ClassCastException e) {
                return null;
            }
    
            return activity.getWindow().getDecorView().findViewById(android.R.id.content);
        }
    
        /**
         * Returns the position in screen. Left abstract to allow for specific implementations such as
         * caching behavior.
         */
        private Point getPositionInScreen() {
            return getPositionInScreen(this);
        }
    
        /**
         * Finds the Point of the parent view, and offsets result by self getX() and getY().
         * @return Point determining position of the passed in view inside all of its ViewParents.
         */
        private Point getPositionInScreen(View view) {
            if (getParent() == null) {
                return new Point();
            }
    
    
            ViewGroup parent;
            try {
                parent = (ViewGroup) view.getParent();
            } catch (Exception e) {
                return new Point();
            }
    
            if (parent == null) {
                return new Point();
            }
    
            Point point = getPositionInScreen(parent);
            point.offset((int) view.getX(), (int) view.getY());
            return point;
        }
    
        /**
         * Users a View reference to create a bitmap, and downscales it using the passed in factor.
         * Uses a Rect to crop the view into the bitmap.
         * @return Bitmap made from view, downscaled by downscaleFactor.
         * @throws NullPointerException
         */
        private Bitmap getDownscaledBitmapForView(View view, Rect crop, float downscaleFactor) throws NullPointerException {
            View screenView = view.getRootView();
    
            int width = (int) (crop.width() * downscaleFactor);
            int height = (int) (crop.height() * downscaleFactor);
    
            if (screenView.getWidth() <= 0 || screenView.getHeight() <= 0 || width <= 0 || height <= 0) {
                throw new NullPointerException();
            }
    
            float dx = -crop.left * downscaleFactor;
            float dy = -crop.top * downscaleFactor;
    
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
            Canvas canvas = new Canvas(bitmap);
            Matrix matrix = new Matrix();
            matrix.preScale(downscaleFactor, downscaleFactor);
            matrix.postTranslate(dx, dy);
            canvas.setMatrix(matrix);
            screenView.draw(canvas);
    
            return bitmap;
        }
    
        /**
         * Sets downscale factor to use pre-blur.
         * See {@link #mDownscaleFactor}.
         */
        public void setDownscaleFactor(float downscaleFactor) {
            this.mDownscaleFactor = downscaleFactor;
            invalidate();
        }
    
        /**
         * Sets blur radius to use on downscaled bitmap.
         * See {@link #mBlurRadius}.
         */
        public void setBlurRadius(int blurRadius) {
            this.mBlurRadius = blurRadius;
            invalidate();
        }
    
        /**
         * Sets FPS to invalidate blur with.
         * See {@link #mFPS}.
         */
        public void setFPS(int fps) {
            this.mFPS = fps;
        }
    
    }
    

    in XML file:

                   <FrameLayout
                            android:id="@+id/fl_uploadedView"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_margin="@dimen/_10sdp">
    
                            <ImageView
                                android:id="@+id/dv_uploadedPic"
                                android:layout_width="match_parent"
                                android:layout_height="@dimen/_150sdp"
                                android:contentDescription="@string/app_name"
                                android:scaleType="centerCrop"
                                android:src="@color/gray" />
    
                            <BlurLayout
                                android:id="@+id/ll_blurView"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_gravity="bottom">
    
                            <TextView
                                android:id="@+id/tv_fileName"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_gravity="left"
                                android:padding="@dimen/_5sdp"
                                android:textSize="@dimen/_10sdp"
                               />
                    </BlurLayout>
                </FrameLayout>
    

    Do not forget to add this to values > attr.xml

    <!--
             Blur Layout start
          -->
        <declare-styleable name="BlurLayout">
            <attr name="downscaleFactor" format="float" />
            <attr name="blurRadius" format="integer" />
            <attr name="fps" format="integer" />
        </declare-styleable>
    
        <!--
           Blur Layout end
        -->
    
    0 讨论(0)
  • 2020-12-24 16:00

    This can be achieved in following steps:

    • Extract the background image of LinearLayout by cropping background Image. Now extend LinearLayout Class.

    • Override OnDraw(Canvas mCanvas) method.

    • Create two methods in your Custom LinearLayout Class:

      1. DrawBitmap
      2. DrawColor.
    • First call the DrawBitmap function by giving the offset you got from ViewPager to background image so that image moves when the use swipe the screen.

    • Finally draw the color with your transparency level

    I hope this will solve your problem.

    Sample Code for this

    How to Blur a View

    0 讨论(0)
  • 2020-12-24 16:03

    Try applyBlur method:

    private void applyBlur(ImageView image) {
        image.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                image.getViewTreeObserver().removeOnPreDrawListener(this);
                image.buildDrawingCache();
    
                Bitmap bmp = image.getDrawingCache();
                blur(bmp, text);
                return true;
            }
        });
    }
    
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private void blur(Bitmap bkg, View view) {
        long startMs = System.currentTimeMillis();
    
        float radius = 20;
    
        Bitmap overlay = Bitmap.createBitmap((int) (view.getMeasuredWidth()),
                (int) (view.getMeasuredHeight()), Bitmap.Config.ARGB_8888);
    
        Canvas canvas = new Canvas(overlay);
    
        canvas.translate(-view.getLeft(), -view.getTop());
        canvas.drawBitmap(bkg, 0, 0, null);
    
        RenderScript rs = RenderScript.create(getActivity());
    
        Allocation overlayAlloc = Allocation.createFromBitmap(
                rs, overlay);
    
        ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
                rs, overlayAlloc.getElement());
    
        blur.setInput(overlayAlloc);
    
        blur.setRadius(radius);
    
        blur.forEach(overlayAlloc);
    
        overlayAlloc.copyTo(overlay);
    
        view.setBackground(new BitmapDrawable(
                getResources(), overlay));
    
        rs.destroy();
    }
    
    0 讨论(0)
提交回复
热议问题