安卓AlertDialog对话框背景模糊的简单实现

先来看看效果如何:

最近对Android又有了一些探索,自从看到iOS上的高斯模糊做得如此奈斯就萌生了在安卓上模仿一下的想法,简单想了一下可以 用这样的思路来做:

  1. 众所周知FrameLayout是能叠加在已经有的View上面的,所以在写UI时用一个FrameLayout 来承载一个ImageView,作为对话框后面的背景,假设这个ImageView的ID为main_dialog_bg。
  2. 获取当前屏幕的截图进行模糊处理,并让main_dialog_bg这个ImageView来显示它,但同时要设置它的透明度为全透明,而且setVisibility(View.GONE); 。
  3. 用户点击弹窗按钮时 执行第2步,然后main_dialog_bg.setVisibility(View.VISIBLE); ,用循环让模糊的背景从全透明转为不透明,再弹出窗口
  4. 用户取消 弹窗时用循环来实现背景透明度从不透明慢慢变成全透明,最后把背景可见性设为GONE

下面是做出来的 一个Demo,效果很棒

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:fitsSystemWindows="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    <!--  这里的RelativeLayout用于主界面的布局,为了方便布局这里直接用了一张图片作为主界面  -->
    <RelativeLayout
        android:layout_below="@id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/iv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@mipmap/main_view" />

    </RelativeLayout>

    <!-- 这里的FrameLayout用于承载对话框的背景 -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/iv_dialog_bg"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </FrameLayout>

</RelativeLayout>

非常重要的地方就是状态栏要设为透明并且在java代码里面写一句

toolbar.setFitsSystemWindows(true);

styles.xml:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowDrawsSystemBarBackgrounds">false</item>
        <!-- 注意!需要将状态栏透明打开 -->
        <item name="android:windowTranslucentStatus">true</item>
    </style>

</resources>

 

MainActivity.java:

package dialog.blur.demo;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {
    private ImageView dialogBg;
    private int originalW;
    private int originalH;
    private Handler mHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        //创建activity先把对话框背景图设为不可见
        dialogBg.setImageAlpha(0);
        dialogBg.setVisibility(View.GONE);
    }
    @SuppressLint("HandlerLeak")
    private void initView() {
        Toolbar toolbar = findViewById(R.id.toolbar);
        dialogBg = findViewById(R.id.iv_dialog_bg);
        setSupportActionBar(toolbar);
        toolbar.setFitsSystemWindows(true);//这条语句和状态栏透明必不可少
        mHandler = new Handler() {

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 0) {
                    dialogBg.setVisibility(View.GONE);
                }
            }
        };
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.toolbar, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.pop:
                handleBlur();//处理背景图
                dialog();//弹出对话框并实现背景图的展现
                break;
            case R.id.exit:
                finish();
                break;
            default:
        }
        return true;
    }

    private Bitmap captureScreen(Activity activity) {
        activity.getWindow().getDecorView().destroyDrawingCache();  //先清理屏幕绘制缓存(重要)
        activity.getWindow().getDecorView().setDrawingCacheEnabled(true);
        Bitmap bmp = activity.getWindow().getDecorView().getDrawingCache();
        //获取原图尺寸
        originalW = bmp.getWidth();
        originalH = bmp.getHeight();
        //对原图进行缩小,提高下一步高斯模糊的效率
        bmp = Bitmap.createScaledBitmap(bmp, originalW / 4, originalH / 4, false);
        return bmp;
    }

    private void setScreenBgLight(Dialog dialog) {
        Window window = dialog.getWindow();
        WindowManager.LayoutParams lp;
        if (window != null) {
            lp = window.getAttributes();
            lp.dimAmount = 0.2f;
            window.setAttributes(lp);
        }
    }

    private void dialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle("弹窗");
        builder.setMessage("这是一个对话框,实现了背景虚化效果。");
        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface p1) {
                //点击对话框外侧区域取消弹窗的监听
                hideBlur();     //背景淡出
            }
        });
        builder.setPositiveButton("好的", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface p1, int p2) {
                //为确定按钮(右)添加点击事件
                hideBlur();     //背景淡出
            }
        });

        Dialog dialog = builder.show();
        setScreenBgLight(dialog);//背景明暗度调整
    }

    private void handleBlur() {
        Bitmap bp = captureScreen(MainActivity.this);
        bp = blur(bp);                      //对屏幕截图模糊处理
        //将模糊处理后的图恢复到原图尺寸并显示出来
        bp = Bitmap.createScaledBitmap(bp, originalW, originalH, false);
        dialogBg.setImageBitmap(bp);
        dialogBg.setVisibility(View.VISIBLE);
        //防止UI线程阻塞,在子线程中让背景实现淡入效果
        asyncRefresh(true);
    }
    private void asyncRefresh(boolean in) {
        //淡出淡入效果的实现
        if(in) {    //淡入效果
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 256; i += 5) {
                        refreshUI(i);//在UI线程刷新视图
                        try {
                            Thread.sleep(4);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        } else {    //淡出效果
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 255; i >= 0; i -= 5) {
                        refreshUI(i);//在UI线程刷新视图
                        try {
                            Thread.sleep(4);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //当淡出效果完毕后发送消息给mHandler把对话框背景设为不可见
                    mHandler.sendEmptyMessage(0);
                }
            }).start();
        }
    }

    private void refreshUI(final int i) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                dialogBg.setImageAlpha(i);
            }
        });
    }

    private void hideBlur() {
        //把对话框背景隐藏
        asyncRefresh(false);
        System.gc();
    }

    private Bitmap blur(Bitmap bitmap) {
        //使用RenderScript对图片进行高斯模糊处理
        Bitmap output = Bitmap.createBitmap(bitmap); // 创建输出图片
        RenderScript rs = RenderScript.create(this); // 构建一个RenderScript对象
        ScriptIntrinsicBlur gaussianBlue = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); //
        // 创建高斯模糊脚本
        Allocation allIn = Allocation.createFromBitmap(rs, bitmap); // 开辟输入内存
        Allocation allOut = Allocation.createFromBitmap(rs, output); // 开辟输出内存
        float radius = 10f;     //设置模糊半径
        gaussianBlue.setRadius(radius); // 设置模糊半径,范围0f<radius<=25f
        gaussianBlue.setInput(allIn); // 设置输入内存
        gaussianBlue.forEach(allOut); // 模糊编码,并将内存填入输出内存
        allOut.copyTo(output); // 将输出内存编码为Bitmap,图片大小必须注意
        rs.destroy();
        //rs.releaseAllContexts(); // 关闭RenderScript对象,API>=23则使用rs.releaseAllContexts()
        return output;
    }
}

 

其他的代码,比如res/menu/toolbar.xml和res/values/color.xml, 就没有必要贴出来了

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
可以在dialog的后面造成模糊效果,模糊实现是基于FastBlur算法实现的。项目地址:https://github.com/tvbarthel/BlurDialogFragment 效果图:使用说明:最简单的使用方式是继承BlurDialogFragment或者SupportBlurDialogFragment。如果你用的是android.app.DialogFragment,那么继承BlurDialogFragment/**  * Simple fragment with blurring effect behind.  */ public class SampleDialogFragment extends BlurDialogFragment {       @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         this.debug(true);         this.setBlurRadius(4);         this.setDownScaleFactor(5.0f);           ...     }       ... }如果是android.support.v4.app.DialogFragment 则继承 SupportBlurDialogFragment/**  * Simple fragment with blurring effect behind.  */ public class SampleDialogFragment extends SupportBlurDialogFragment {       @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         this.debug(true);         this.setBlurRadius(4);         this.setDownScaleFactor(5.0f);           ...     }       ... }如果你不想使用继承的方式可以直接使用BlurEngine自定义一个DialogFragment/**  * Your blur fragment directly using BlurEngine.  */ public class SampleDialogFragment extends MyCustomDialogFragment {        /**      * Engine used to blur.      */     private BlurDialogEngine mBlurEngine;       @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);           mBlurEngine = new BlurDialogEngine(getActivity());         mBlurEngine.debug(mDebugEnable);         mBlurEngine.setBlurRadius(8);         mBlurEngine.setDownScaleFactor(8f);     }       @Override     public void onResume() {         super.onResume();         mBlurEngine.onResume(getRetainInstance());     }        @Override     public void onDismiss(DialogInterface dialog) {         super.onDismiss(dialog);         mBlurEngine.onDismiss();     }       @Override     public void onDestroy() {         super.onDestroy();         mBlurEngine.onDestroy();     }       @Override     public void onDestroyView() {         if (getDialog() != null) {             getDialog().setDismissMessage(null);         }         super.onDestroyView();     }       ... }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值