【问题标题】:Blur Background Behind AlertDialog模糊 AlertDialog 背后的背景
【发布时间】:2013-10-19 02:58:07
【问题描述】:

我们从 API 14 中知道,下方模糊已被弃用

dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 

是否有任何替代方法可以使对话框后面的屏幕模糊 我试过FAST blur

【问题讨论】:

    标签: android android-alertdialog blur


    【解决方案1】:

    试试这个方法会帮助你我正在使用这个

    创建一个styles.xml

    <style name="Theme.D1NoTitleDim" parent="android:style/Theme.Translucent">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:background">@android:color/transparent</item>        
    </style>
    

    然后在你的对话框中

    dialog = new Dialog(context,styles); 
    

    这对我来说很好用

    更多我建议你看这个Example

    【讨论】:

    • @hi Gaurav Thks 但它使背景变暗而不是模糊......任何其他建议 plz
    • 所以你想要任何你有的图片请发布
    • 这意味着使 dim 是唯一可能的解决方案
    • 你能在 xml 文件中制作自己的对话框吗?使用模糊的 PNG 来赋予它效果。在布局之上的布局。
    【解决方案2】:

    更新:

    我们也可以使用renderscript api 来模糊 API 级别 >= 17 的背景,并使用 fastblur 来处理 API 级别

    - Github Project

    - Blog

    使用 FastBlur 的步骤

    1) 使用以下代码拍摄背景快照

    private static Bitmap takeScreenShot(Activity activity)
        {
            View view = activity.getWindow().getDecorView();
            view.setDrawingCacheEnabled(true);
            view.buildDrawingCache();
            Bitmap b1 = view.getDrawingCache();
            Rect frame = new Rect();
            activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
            int statusBarHeight = frame.top;
            int width = activity.getWindowManager().getDefaultDisplay().getWidth();
            int height = activity.getWindowManager().getDefaultDisplay().getHeight();
    
            Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height  - statusBarHeight);
            view.destroyDrawingCache();
            return b;
        }
    

    像这样使用它Bitmap map=takeScreenShot(BlurImageView.this);// 你的活动名称

    2) 调用方法Bitmap fast=fastblur(map, 10); 得到它来自Here

        public Bitmap fastblur(Bitmap sentBitmap, int radius) {
            Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
    
            if (radius < 1) {
                return (null);
            }
    
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
    
            int[] pix = new int[w * h];
            Log.e("pix", w + " " + h + " " + pix.length);
            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 rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
            int vmin[] = new int[Math.max(w, h)];
    
            int divsum = (div + 1) >> 1;
            divsum *= divsum;
            int dv[] = new int[256 * divsum];
            for (i = 0; i < 256 * divsum; i++) {
                dv[i] = (i / divsum);
            }
    
            yw = yi = 0;
    
            int[][] stack = new int[div][3];
            int stackpointer;
            int stackstart;
            int[] sir;
            int rbs;
            int r1 = radius + 1;
            int routsum, goutsum, boutsum;
            int rinsum, ginsum, binsum;
    
            for (y = 0; y < h; y++) {
                rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
                for (i = -radius; i <= radius; i++) {
                    p = pix[yi + Math.min(wm, Math.max(i, 0))];
                    sir = stack[i + radius];
                    sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
            sir[2] = (p & 0x0000ff);
            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 & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);
    
                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++) {
                rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
                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++) {
                    // Preserve alpha channel: ( 0xff000000 & pix[yi] )
                    pix[yi] = ( 0xff000000 & 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;
                }
            }
    
            Log.e("pix", w + " " + h + " " + pix.length);
            bitmap.setPixels(pix, 0, w, 0, 0, w, h);
    
            return (bitmap);
        }
    

    3) 最后点击Button

    btnblur.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
    
                    AlertDialog.Builder builder=new AlertDialog.Builder(BlurImageView.this,R.style.Theme_D1NoTitleDim);
                    builder.setTitle("Content");
                    builder.setMessage("CLICK OK to Exit");
                    builder.setPositiveButton("ON", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            back_dim_layout.setVisibility(View.GONE);
                            dialog.cancel();
                        }
                    });
                    alert=builder.create();
                    Bitmap map=takeScreenShot(BlurImageView.this);
    
                    Bitmap fast=fastblur(map, 10);
                    final Drawable draw=new BitmapDrawable(getResources(),fast);
                    alert.getWindow().setBackgroundDrawable(draw);
                    alert.show();
                }
            });
    

    就是这样,现在您可以看到 Activity 背后的模糊图像

    希望这对任何人都有帮助...

    【讨论】:

    • 这种实现是否会导致应用出现一些滞后?当我尝试实现这个时,应用程序有点慢。
    • @user2247689 这是因为 fastBlur 方法需要一些时间来执行
    • 你找到解决办法了吗?顺便说一句back_dim_layout.setVisibility(View.GONE); 在这里?
    • @user2247689 你可以试试这个教程参考nicolaspomepuy.fr/?p=18 。它实际上存储图像使其模糊。
    • getDefaultDisplay().getWidth()getDefaultDisplay().getHeight() 已弃用。请改用getRealMetrics() 方法:developer.android.com/reference/android/view/…
    【解决方案3】:

    nitesh 的这个解决方案如下所示

    但是,如果您无法向 center(像我一样)发出警报,也请检查我的答案, 这是Here

    我所做的是,

    使用了两个alertDialogs 一个用于模糊效果(供getWindow() 使用)现在无法显示(我删除了它的setContentView / 可以使用透明背景)

    另一个是真实的alertDialog经过模糊效果后的显示

    输出

    【讨论】:

      【解决方案4】:

      为了快速模糊并解决对话框出现在屏幕顶部的问题,我认为有一个更简单的解决方案:

      // Custom Dialog to be called in the Activity choosed.
      public class CustomDialog {
          private Dialog dialog;
      
          public CustomDialog(AppCompatActivity activity) {
              dialog = new Dialog(activity);
              dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
              View viewCustomDialog = LayoutInflater.from(activity).inflate(R.layout.custom_dialog, null);
              dialog.setContentView(viewCustomDialog);
      
              RelativeLayout rootView = viewCustomDialog.findViewById(R.id.rootView);
      
              WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
              layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
              layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
              layoutParams.gravity = Gravity.CENTER;
              dialog.getWindow().setAttributes(layoutParams);
      
              // First get bitmap with blur filter applied, using the function blur presented here,  
              // or another function.
              // Activity parameter is the Activity for which you call dialog.show();
              Bitmap bitmap = Utils.blur(activity);
      
              // Get bitmap height.
              int bitmapHeight = bitmap.getHeight();
      
              dialog.setOnShowListener(dialogInterface -> {
                  // When dialog is shown, before set new blurred image for background drawable, 
                  // the root view height and dialog margin are saved.
                  int rootViewHeight = rootView.getHeight();
                  int marginLeftAndRight = dialog.getWindow().getDecorView().getPaddingLeft();
      
                  // Set new blurred image for background drawable.
                  dialog.getWindow().setBackgroundDrawable(new BitmapDrawable(builder.context.getResources(), bitmap));
      
                  // After get positions and heights, recover and rebuild original marginTop position, 
                  // that is (bitmapHeight - rootViewHeight) / 2.
                  // Also recover and rebuild Dialog original left and right margin.
                  FrameLayout.LayoutParams rootViewLayoutParams = (FrameLayout.LayoutParams)rootView.getLayoutParams();
                  rootViewLayoutParams.setMargins(marginLeftAndRight, (bitmapHeight - rootViewHeight) / 2, marginLeftRight, 0);
              });
      
              dialog.show();
          }
      }
      

      模糊方法:

      public static Bitmap blur(AppCompatActivity activity) {
         Bitmap bitmap = Utils.takeScreenShot(activity);
      
         RenderScript renderScript = RenderScript.create(activity);
      
         // This will blur the bitmapOriginal with a radius of 16 and save it in bitmapOriginal
         final Allocation input = Allocation.createFromBitmap(renderScript, bitmap); // Use this constructor for best performance, because it uses USAGE_SHARED mode which reuses memory
         final Allocation output = Allocation.createTyped(renderScript, input.getType());
         final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
         script.setRadius(16f);
         script.setInput(input);
         script.forEach(output);
         output.copyTo(bitmap);
      
         return bitmap;
      }
      

      TakeScreenShot 方法:

      public static Bitmap takeScreenShot(AppCompatActivity activity) {
          View view = activity.getWindow().getDecorView();
          view.setDrawingCacheEnabled(true);
          view.buildDrawingCache();
          Bitmap bitmap = view.getDrawingCache();
          Rect frame = new Rect();
          activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
          int statusBarHeight = frame.top;
          int[] widthHeight = getScreenSize(activity);
          Bitmap bitmapResult = Bitmap.createBitmap(bitmap, 0, statusBarHeight, widthHeight[0], widthHeight[1]  - statusBarHeight);
          view.destroyDrawingCache();
          return bitmapResult;
      }   
      

      GetScreenSize 方法:

      public static int[] getScreenSize(Context context) {
          int[] widthHeight = new int[2];
          widthHeight[WIDTH_INDEX] = 0;
          widthHeight[HEIGHT_INDEX] = 0;
      
          WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
          Display display = windowManager.getDefaultDisplay();
      
          Point size = new Point();
          display.getSize(size);
          widthHeight[WIDTH_INDEX] = size.x;
          widthHeight[HEIGHT_INDEX] = size.y;
      
          if (!isScreenSizeRetrieved(widthHeight)) {
              DisplayMetrics metrics = new DisplayMetrics();
              display.getMetrics(metrics);
              widthHeight[0] = metrics.widthPixels;
              widthHeight[1] = metrics.heightPixels;
          }
      
          if (!isScreenSizeRetrieved(widthHeight)) {
              widthHeight[0] = display.getWidth(); // deprecated
              widthHeight[1] = display.getHeight(); // deprecated
          }
      
          return widthHeight;
      }   
      
      private static boolean isScreenSizeRetrieved(int[] widthHeight) {
          return widthHeight[WIDTH_INDEX] != 0 && widthHeight[HEIGHT_INDEX] != 0;
      }
      

      而为了使用 RenderScript (To blur),你必须在 App 的 build.gradle 中添加:

      defaultConfig {
          ...     
          renderscriptTargetApi 19
          renderscriptSupportModeEnabled true
      }
      

      【讨论】:

        【解决方案5】:

        试试这个

            dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            dialog.setContentView(view);
            dialog.setCancelable(true);
            Window window = dialog.getWindow();
            WindowManager.LayoutParams wlp = window.getAttributes();
        
            wlp.gravity = Gravity.CENTER;
            wlp.flags &= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
            window.setAttributes(wlp);
            dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            dialog.show();
        }
        

        【讨论】:

        • 尝试更详细地解释您的答案,而不是只是提供代码。 为什么您的代码有效? 为什么这是首选的解决方案?
        猜你喜欢
        • 2021-06-27
        • 1970-01-01
        • 2017-03-18
        • 1970-01-01
        • 2015-10-26
        • 1970-01-01
        • 2016-04-22
        • 2018-04-24
        • 2019-01-20
        相关资源
        最近更新 更多