Android中毛玻璃效果的两种实现

Android中毛玻璃效果主要有两种实现方式。
1.使用JAVA算法FastBlur实现
方法1 先将图片缩小,然后放大图片,再设置为控件背景以达到更模糊的效果,同时也提升模糊算法的处理效率。
2.使用Android自带类RenderScript 实现
方法2 模糊半径只能设置1-25。

对比下来同样的模糊半径 ,方法1 的模糊效果更好,且方法1 的模糊半径可以设置范围更大。示例代码如下:
1.activity中调用

private void testImageBlur() {
        Log.i(TAG, "testImageBlur() 11");
        Bitmap bitmapOrigin1 = getTestImage();
        //1.显示原图
        mImageOrigin.setImageBitmap(bitmapOrigin1);
        Log.i(TAG, "testImageBlur() 22 bitmapOrigin1.isRecycled:" + bitmapOrigin1.isRecycled());
        final float RADIUS = 20;
        Bitmap bitmapOrigin2 = getTestImage();
        Bitmap bitmapFastBlur = BitmapUtil.blurFastBlur(this, bitmapOrigin2, 20);
        //2.显示使用FastBlur处理后 高斯模糊图片
        mImageFastBlurResult.setImageBitmap(bitmapFastBlur);

        Bitmap bitmapOrigin3 = getTestImage();
        Bitmap bitmapRenderScriptBlur = BitmapUtil.blurRenderScript(this, bitmapOrigin3, 25);
        //3.显示 RenderScript 处理后的高斯模糊图片
        mImageRenderScriptResult.setImageBitmap(bitmapRenderScriptBlur);
        Log.i(TAG, "testImageBlur() 33 bitmapOrigin3.isRecycled:" + bitmapOrigin3.isRecycled()
                + " bitmapOrigin1.isRecycled():" + bitmapOrigin1.isRecycled());
    }


2.BitmapUtil.java 类

public class BitmapUtil {
    private static final String TAG = "BitmapUtil";

    public static BitmapDrawable getConfirmDialogBg(Context context) {
        return getScreenBlurBg(context, 30.0f, 1676, 160, 834, 1094);
    }

    /**
     * 使用 获取全屏高斯模糊的图片 BitmapDrawable
     *
     * @param activity
     * @return
     */
    public static BitmapDrawable getScreenBlurBg(Activity activity) {
        WeakReference<Bitmap> screenBitmap = new WeakReference(FastBlurUtil.takeScreenShot(activity));
        Log.i(TAG, "getScreenBlurBg 00 screenBitmap:" + screenBitmap);
        if (null == screenBitmap) {
            return null;
        }
        Log.i(TAG, "getScreenBlurBg 11 screenBitmap:" + screenBitmap);
        long startMs = System.currentTimeMillis();
        float radius = 10.0F;

        Bitmap bitmapSmall = small(screenBitmap.get());
        Bitmap bitmapBlur = FastBlurUtil.fastBlur(bitmapSmall, radius);
        WeakReference<Bitmap> overlay = new WeakReference(FastBlurUtil.getDimBitmap(bitmapBlur, 0.2F));
        Log.i(TAG, "getScreenBlurBg 22 =====blur time:" + (System.currentTimeMillis() - startMs));
        try {
            if (screenBitmap.get() != null && !screenBitmap.get().isRecycled()) {
                screenBitmap.get().recycle();
            }
            if (null != bitmapSmall && !bitmapSmall.isRecycled()) {
                bitmapSmall.recycle();
            }
            if (null != bitmapBlur && !bitmapBlur.isRecycled()) {
                bitmapBlur.recycle();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        BitmapDrawable rst = new BitmapDrawable(activity.getResources(), overlay.get());
        return rst;
    }

    /**
     * 获取屏幕指定区域高斯模糊的图片 BitmapDrawable
     *
     * @param context
     * @param blurRadius 模糊半径
     * @param xOffset    指定区域的左上角顶点X坐标偏移
     * @param yOffset    指定区域的左上角顶点Y坐标偏移
     * @param width      指定区域的宽度
     * @param height     指定区域的高度
     * @return
     */
    public static BitmapDrawable getScreenBlurBg(Context context, float blurRadius, int xOffset, int yOffset, int width, int height) {
        Bitmap screenBitmap = FastBlurUtil.screenshot(context);
        if (null == screenBitmap) {
            return null;
        }
        Bitmap b1 = crop(screenBitmap, xOffset, yOffset, width, height);
        Bitmap overlay = FastBlurUtil.fastBlur(bitmapMergeWithColor(b1), blurRadius);
//        Bitmap overlay = FastBlurUtility.getDimBitmap(FastBlurUtility.fastBlur(small(bitmapMerge(b1, b2)), radius), 0.2F);
        BitmapDrawable rst = new BitmapDrawable(context.getResources(), getRoundedCornerBitmap(overlay));
        return rst;
    }

    /**
     * 在给定的bitmap中剪裁指定区域
     *
     * @param source
     * @param xOffset 指定区域的左上角顶点X坐标偏移
     * @param yOffset 指定区域的左上角顶点Y坐标偏移
     * @param width   指定区域的宽度
     * @param height  指定区域的高度
     * @return
     */
    public static Bitmap crop(Bitmap source, int xOffset, int yOffset, int width, int height) {
        return Bitmap.createBitmap(source, xOffset, yOffset, width, height);
    }

    /**
     * 缩小bitmap,可以使用此方法先将图片缩小,再设置为控件背景以达到更模糊的效果
     *
     * @param bitmap
     * @return
     */
    private static Bitmap small(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.postScale(0.25F, 0.25F);
        Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizeBmp;
    }

    /**
     * 图片圆角化
     *
     * @param bitmap
     * @return
     */
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {

        final float roundPx = 24f;
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xFFFFFFFF;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }

    /**
     * 将bitmap与指定颜色混合
     *
     * @param b1
     * @return
     */
    private static Bitmap bitmapMergeWithColor(Bitmap b1) {
        if (!b1.isMutable()) {
            b1 = b1.copy(Bitmap.Config.ARGB_8888, true);
        }
        Canvas canvas = new Canvas(b1);
        canvas.drawARGB(79, 255, 255, 255);
        canvas.save();
        canvas.restore();
        return b1;
    }

    /**
     * 使用 fastBlur 接口实现高斯模糊效果
     *
     * @param context
     * @param orginBitmap 需要做模糊效果的原始 bitmap
     * @param radius      模糊半径
     * @return 模糊后的bitmap
     */
    public static Bitmap blurFastBlur(Context context, Bitmap orginBitmap, float radius) {
        Log.i(TAG, "getScreenBlurBg 00 orginBitmap:" + orginBitmap);
        if (null == orginBitmap) {
            return null;
        }
        Log.i(TAG, "getScreenBlurBg 11 orginBitmap:" + orginBitmap);
        long startMs = System.currentTimeMillis();
        //先将图片缩小,再设置为控件背景以达到更模糊的效果,同时也提升模糊算法的处理效率
        Bitmap bitmapSmall = small(orginBitmap);
        Bitmap bitmapBlur = FastBlurUtil.fastBlur(bitmapSmall, radius);
        WeakReference<Bitmap> overlay = new WeakReference(FastBlurUtil.getDimBitmap(bitmapBlur, 0.2F));
        //WeakReference<Bitmap> overlay = new WeakReference(bitmapBlur);
        Log.i(TAG, "getScreenBlurBg 22 =====blur time:" + (System.currentTimeMillis() - startMs));
        try {
            if (orginBitmap != null && !orginBitmap.isRecycled()) {
                orginBitmap.recycle();
            }
            if (null != bitmapSmall && !bitmapSmall.isRecycled()) {
                bitmapSmall.recycle();
            }
            if (null != bitmapBlur && !bitmapBlur.isRecycled()) {
                bitmapBlur.recycle();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return overlay.get();
    }

    /**
     * 使用Android自带 RenderScript 接口实现高斯模糊效果
     *
     * @param context
     * @param smallBitmap 需要做模糊效果的bitmap
     * @param radius      模糊半径
     * @return 模糊后的bitmap
     */
    public static Bitmap blurRenderScript(Context context, Bitmap smallBitmap, float radius) {
        // Create a new bitmap that is a copy of the original bitmap
        Bitmap bitmap = smallBitmap.copy(Bitmap.Config.ARGB_8888, true);

        // Initialize RenderScript
        RenderScript rs = RenderScript.create(context);

        // Create an empty allocation that will hold the original bitmap
        Allocation input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);

        // Create an empty allocation that will hold the blurred bitmap
        Allocation output = Allocation.createTyped(rs, input.getType());

        // Load the script in the Allocation
        ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        script.setInput(input);

        // Set the blur radius
        //float radius = 20f; // 20 works well for me

        // Start the Script Intrinsic Blur
        script.setRadius(radius);
        script.forEach(output);

        // Copy the script result into the blurred bitmap
        output.copyTo(bitmap);

        // Recycle the original bitmap
        smallBitmap.recycle();

        // After all of this, we can return the now-blurred bitmap
        return bitmap;
    }
}

3.FastBlurUtil.java 类

public class FastBlurUtil {
    public FastBlurUtil() {
    }

    public static Bitmap getBlurBackgroundDrawer(Context context) {
        Bitmap bmp = screenshot(context);
        return startBlurBackground(bmp);
    }

    public static Bitmap screenshot(Context context) {
        int[] dim = new int[]{ScreenUtils.getScreenWidth(context), ScreenUtils.getScreenHeight(context)};
        String surfaceClassName = "";
        if (VERSION.SDK_INT <= 17) {
            surfaceClassName = "android.view.Surface";
        } else {
            surfaceClassName = "android.view.SurfaceControl";
        }

        try {
            Class<?> c = Class.forName(surfaceClassName);
            Method method = c.getMethod("screenshot", Rect.class, Integer.TYPE, Integer.TYPE, Integer.TYPE);
            method.setAccessible(true);
            Bitmap bitmap = (Bitmap)method.invoke((Object)null, new Rect(0, 0, dim[0], dim[1]), dim[0], dim[1], 0);
            if(null == bitmap){
                return null;
            }
            bitmap = bitmap.copy(Config.ARGB_8888, true);
            return bitmap;
        } catch (NoSuchMethodException | InvocationTargetException | ClassNotFoundException | IllegalAccessException var6) {
            var6.printStackTrace();
            return null;
        }
    }

    public static Bitmap takeScreenShot(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap b1 = view.getDrawingCache();
        int width = activity.getResources().getDisplayMetrics().widthPixels;
        int height = activity.getResources().getDisplayMetrics().heightPixels + getNavigationBarOffset(activity);
        Bitmap bmp = Bitmap.createBitmap(b1, 0, 0, width, height);
        view.destroyDrawingCache();
        return bmp;
    }

    @RequiresApi(
            api = 26
    )
    private static Bitmap startBlurBackground(Bitmap bkg) {
        long startMs = System.currentTimeMillis();
        float radius = 10.0F;
        Bitmap overlay = getDimBitmap(fastBlur(small(bkg), radius), 0.2F);
        Log.i("FastBlurUtility", "=====blur time:" + (System.currentTimeMillis() - startMs));
        return overlay;
    }

    private static Bitmap big(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.postScale(4.0F, 4.0F);
        Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizeBmp;
    }

    private static Bitmap small(Bitmap bitmap) {
        Matrix matrix = new Matrix();
        matrix.postScale(0.25F, 0.25F);
        Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        return resizeBmp;
    }

    private static int getStatusBarHeight(Activity activity) {
        int result = 0;
        int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = activity.getResources().getDimensionPixelSize(resourceId);
        }

        return result;
    }

    private static int getNavigationBarOffset(Activity activity) {
        int result = 0;
        Resources resources = activity.getResources();
        if (VERSION.SDK_INT >= 21) {
            int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
            if (resourceId > 0) {
                result = resources.getDimensionPixelSize(resourceId);
            }
        }

        return result;
    }

    /**
     * 每个像素设置模糊效果
     * @param bitmap 原图
     * @param radiusf 模糊半径
     * @return 模糊处理后的效果图
     */
    public static Bitmap fastBlur(Bitmap bitmap, float radiusf) {
        if (bitmap == null) {
            return null;
        } else {
            int radius = (int)radiusf;
            if (radius < 1) {
                return null;
            } else {
                int w = bitmap.getWidth();
                int h = bitmap.getHeight();
                int[] pix = new int[w * h];
                bitmap.getPixels(pix, 0, w, 0, 0, w, h);
                int wm = w - 1;
                int hm = h - 1;
                int wh = w * h;
                int div = radius + radius + 1;
                int[] r = new int[wh];
                int[] g = new int[wh];
                int[] b = new int[wh];
                int[] vmin = new int[Math.max(w, h)];
                int divsum = div + 1 >> 1;
                divsum *= divsum;
                int[] dv = new int[256 * divsum];

                int i;
                for(i = 0; i < 256 * divsum; ++i) {
                    dv[i] = i / divsum;
                }

                int yi = 0;
                int yw = 0;
                int[][] stack = new int[div][3];
                int r1 = radius + 1;

                int rsum;
                int gsum;
                int bsum;
                int x;
                int y;
                int p;
                int stackpointer;
                int stackstart;
                int[] sir;
                int rbs;
                int routsum;
                int goutsum;
                int boutsum;
                int rinsum;
                int ginsum;
                int binsum;
                for(y = 0; y < h; ++y) {
                    bsum = 0;
                    gsum = 0;
                    rsum = 0;
                    boutsum = 0;
                    goutsum = 0;
                    routsum = 0;
                    binsum = 0;
                    ginsum = 0;
                    rinsum = 0;

                    for(i = -radius; i <= radius; ++i) {
                        p = pix[yi + Math.min(wm, Math.max(i, 0))];
                        sir = stack[i + radius];
                        sir[0] = (p & 16711680) >> 16;
                        sir[1] = (p & '\uff00') >> 8;
                        sir[2] = p & 255;
                        rbs = r1 - Math.abs(i);
                        rsum += sir[0] * rbs;
                        gsum += sir[1] * rbs;
                        bsum += sir[2] * rbs;
                        if (i > 0) {
                            rinsum += sir[0];
                            ginsum += sir[1];
                            binsum += sir[2];
                        } else {
                            routsum += sir[0];
                            goutsum += sir[1];
                            boutsum += sir[2];
                        }
                    }

                    stackpointer = radius;

                    for(x = 0; x < w; ++x) {
                        r[yi] = dv[rsum];
                        g[yi] = dv[gsum];
                        b[yi] = dv[bsum];
                        rsum -= routsum;
                        gsum -= goutsum;
                        bsum -= boutsum;
                        stackstart = stackpointer - radius + div;
                        sir = stack[stackstart % div];
                        routsum -= sir[0];
                        goutsum -= sir[1];
                        boutsum -= sir[2];
                        if (y == 0) {
                            vmin[x] = Math.min(x + radius + 1, wm);
                        }

                        p = pix[yw + vmin[x]];
                        sir[0] = (p & 16711680) >> 16;
                        sir[1] = (p & '\uff00') >> 8;
                        sir[2] = p & 255;
                        rinsum += sir[0];
                        ginsum += sir[1];
                        binsum += sir[2];
                        rsum += rinsum;
                        gsum += ginsum;
                        bsum += binsum;
                        stackpointer = (stackpointer + 1) % div;
                        sir = stack[stackpointer % div];
                        routsum += sir[0];
                        goutsum += sir[1];
                        boutsum += sir[2];
                        rinsum -= sir[0];
                        ginsum -= sir[1];
                        binsum -= sir[2];
                        ++yi;
                    }

                    yw += w;
                }

                for(x = 0; x < w; ++x) {
                    bsum = 0;
                    gsum = 0;
                    rsum = 0;
                    boutsum = 0;
                    goutsum = 0;
                    routsum = 0;
                    binsum = 0;
                    ginsum = 0;
                    rinsum = 0;
                    int yp = -radius * w;

                    for(i = -radius; i <= radius; ++i) {
                        yi = Math.max(0, yp) + x;
                        sir = stack[i + radius];
                        sir[0] = r[yi];
                        sir[1] = g[yi];
                        sir[2] = b[yi];
                        rbs = r1 - Math.abs(i);
                        rsum += r[yi] * rbs;
                        gsum += g[yi] * rbs;
                        bsum += b[yi] * rbs;
                        if (i > 0) {
                            rinsum += sir[0];
                            ginsum += sir[1];
                            binsum += sir[2];
                        } else {
                            routsum += sir[0];
                            goutsum += sir[1];
                            boutsum += sir[2];
                        }

                        if (i < hm) {
                            yp += w;
                        }
                    }

                    yi = x;
                    stackpointer = radius;

                    for(y = 0; y < h; ++y) {
                        pix[yi] = -16777216 & pix[yi] | dv[rsum] << 16 | dv[gsum] << 8 | dv[bsum];
                        rsum -= routsum;
                        gsum -= goutsum;
                        bsum -= boutsum;
                        stackstart = stackpointer - radius + div;
                        sir = stack[stackstart % div];
                        routsum -= sir[0];
                        goutsum -= sir[1];
                        boutsum -= sir[2];
                        if (x == 0) {
                            vmin[y] = Math.min(y + r1, hm) * w;
                        }

                        p = x + vmin[y];
                        sir[0] = r[p];
                        sir[1] = g[p];
                        sir[2] = b[p];
                        rinsum += sir[0];
                        ginsum += sir[1];
                        binsum += sir[2];
                        rsum += rinsum;
                        gsum += ginsum;
                        bsum += binsum;
                        stackpointer = (stackpointer + 1) % div;
                        sir = stack[stackpointer];
                        routsum += sir[0];
                        goutsum += sir[1];
                        boutsum += sir[2];
                        rinsum -= sir[0];
                        ginsum -= sir[1];
                        binsum -= sir[2];
                        yi += w;
                    }
                }

                bitmap.setPixels(pix, 0, w, 0, 0, w, h);
                return bitmap;
            }
        }
    }

    @RequiresApi(
            api = 26
    )
    public static Bitmap getDimBitmap(Bitmap background, float dimAmount) {
        if (background == null) {
            return null;
        } else {
            int bgWidth = background.getWidth();
            int bgHeight = background.getHeight();
            Bitmap newbmp = Bitmap.createBitmap(bgWidth, bgHeight, Config.ARGB_8888);
            Canvas cv = new Canvas(newbmp);
            cv.drawBitmap(background, 0.0F, 0.0F, (Paint)null);
            cv.drawColor(Color.argb(dimAmount, 0.0F, 0.0F, 0.0F));
            cv.save();
            cv.restore();
            return newbmp;
        }
    }
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用以下步骤在Android实现毛玻璃效果的对话框: 1. 首先,在你的项目添加依赖项,以使用GlassActionBar库。在app级别的build.gradle文件添加以下代码: ```groovy implementation 'com.github.glomadrian:GlassActionBar:0.5@aar' ``` 2. 在你的布局文件,使用`FrameLayout`作为根布局,并将`GlassFrameLayout`作为子布局。例如: ```xml <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.github.glaucous.androidframework.ui.widget.GlassFrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 在这里添加对话框的内容 --> </com.github.glaucous.androidframework.ui.widget.GlassFrameLayout> </FrameLayout> ``` 3. 接下来,在你的Activity,设置透明状态栏和将ActionBar隐藏。例如: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置透明状态栏 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } // 隐藏ActionBar if (getSupportActionBar() != null) { getSupportActionBar().hide(); } setContentView(R.layout.activity_main); } ``` 4. 最后,在Activity的`onCreateOptionsMenu()`方法,将对话框的背景设置为毛玻璃效果。例如: ```java @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); // 获取对话框的背景视图 View glassView = findViewById(R.id.glass_view); // 设置毛玻璃效果 GlassActionBarHelper.makeTransparentActionBar(this, glassView, R.drawable.your_dialog_background); return true; } ``` 这样,你就可以在Android实现毛玻璃效果的对话框了。记得替换代码的布局文件和背景资源为你自己的内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值