Android Blur View(模糊 View 后面的背景)

标签 android blur android-image android-bitmap blurry

我正在尝试使图像的底部像图像中一样模糊,以便顶部的 View 。

我尝试使用 Rendenscript 对其进行模糊处理,但我无法仅对 View 后面的部分进行模糊处理。 :(

我见过很多图书馆,但几乎所有图书馆都模糊了整个图像,但不是图像的一部分。

此外,一个重要的部分是我在 ViewPager 中使用它,因此需要像 this in IOS 这样的快速和动态的东西。当它背后的图像发生变化时,它会重新绘制自己。

感谢任何帮助。感谢您的光临!

我的 xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/image"
        android:src="@drawable/broadstairs"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:layout_centerInParent="true"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:text="Hello World"
        android:gravity="center"
        android:layout_alignParentBottom="true"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        android:textSize="36sp"/>
</RelativeLayout>

我的代码:

模糊生成器.java

public class BlurBuilder {
    private static final float BITMAP_SCALE = 0.1f;
    private static final float BLUR_RADIUS = 7.5f;

    public static Bitmap blur(Context context, Bitmap image) {
        int width = Math.round(image.getWidth() * BITMAP_SCALE);
        int height = Math.round(image.getHeight() * BITMAP_SCALE);

        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);

        RenderScript rs = RenderScript.create(context);
        ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
        theIntrinsic.setRadius(BLUR_RADIUS);
        theIntrinsic.setInput(tmpIn);
        theIntrinsic.forEach(tmpOut);
        tmpOut.copyTo(outputBitmap);

        return outputBitmap;
    }

    @SuppressLint("NewApi")
    public static void blur(final Context context, final Bitmap bitmap, final View view) {

        new AsyncTask<Void, Void, Bitmap>() {

            @Override
            protected Bitmap doInBackground(Void... params) {
                Paint paint = new Paint();
                paint.setFilterBitmap(true);
                Bitmap cropImage = Bitmap.createBitmap(bitmap, 0, bitmap.getHeight() - view.getHeight(), bitmap.getWidth(), view.getHeight());

                return BlurBuilder.blur(context, cropImage);
            }


            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                if (bitmap != null) {
                    int sdk = android.os.Build.VERSION.SDK_INT;
                    if (sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
                        view.setBackgroundDrawable(new BitmapDrawable(context.getResources(), bitmap));
                    } else {
                        view.setBackground(new BitmapDrawable(context.getResources(), bitmap));
                    }

                }

            }
        }.execute();


    }

}

在我的 MainActivity 的 onCreate 中,我这样做:

BlurBuilder.blur(BitmapActivity.this, ((BitmapDrawable) mView.getDrawable()).getBitmap(), mDummyView);

结果如下:

enter image description here

最佳答案

将这两个类添加到您的应用中,

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;
    }

}

在 XML 文件中:

               <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>

不要忘记将其添加到 值> 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
    -->

关于Android Blur View(模糊 View 后面的背景),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31808955/

相关文章:

Android:在大位图上绘制,2 层,最好的方法?

android - 如何在非相机应用程序中使用 Android 相机 API?

Android:你能通过电话发送/接收数据吗?

android - ListView、BaseAdapter、getViewTypeCount() - 如何强制适配器再次检查 getViewTypeCount()?

android - 即使在 gradle 中添加支持和设计后,如何让 Android TabLayout 工作?

javascript - 类型错误 : blur is not a function

jquery - 如何在 chrome/safari 中展开选择框时折叠它?

java - 当我第二次运行对话框时,我的 Android 应用程序崩溃了

java - Android Renderscript 速度不一致

android - 图片无法在android中的服务器上上传