高斯模糊

931 阅读2分钟

前置知识

概述

高斯模糊主要应用于: 对单个View的内容进行模糊, 对Window的背景进行模糊, 对Window后面的所有内容进行模糊.
1. 对单个View的内容进行模糊
  • 如果以 Android 12(API 级别 31)及更高版本为目标平台,直接使用系统内置 RenderEffect 类
  • 否则需要使用 renderscript-intrinsics-replacement-toolkit image.png
  • 使用 RenderEffect 设置View的模糊效果
    • View.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode))

    • View.setRenderEffect(null) 会取消模糊效果

      class RenderEffectActivity : AppCompatActivity() {
          lateinit var img: ImageView
          lateinit var tv: TextView
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_render_effect)
              img = findViewById(R.id.img)
              img.setOnClickListener{
                  img.setRenderEffect(null)
              }
              tv = findViewById(R.id.tv)
              tv.setOnClickListener{
                  tv.setRenderEffect(null)
              }
          }
      
          private val radius: FloatArray = floatArrayOf(1.0F, 2.0F, 4.0F, 8.0F, 16.0F)
          private var index: Int = -1
          fun showRenderEffect(view: View) {
              index = (index+1) % radius.size
              img.setRenderEffect(RenderEffect.createBlurEffect(radius[index], radius[index], Shader.TileMode.MIRROR))
              tv.setRenderEffect(RenderEffect.createBlurEffect(radius[index], radius[index], Shader.TileMode.MIRROR))
          }
      }
      

      Screenshot_2023-03-10-18-15-54-909_com.example.jet2022.jpg

2. 对Window的背景进行模糊
  1. 不要设置window.attributes.blurBehindRadius即可
  2. 其他代码保持和'3. 对Window后面的所有内容进行模糊'保持一致即可
//window.attributes.blurBehindRadius 用于设置Activity的窗口后面所有内容的模糊
//window.attributes.blurBehindRadius = mBlurBehindRadius;
  1. 运行截图 img_v3_02m8_4658565b-a3c3-4cba-acfa-4b5d8e94d37g.jpg
3. 对Window后面的所有内容进行模糊.
  1. 2和3使用的注意事项: image.png

  2. 实际代码

    //Activity声明
    <activity
        android:name="com.example.windowblur.BlurActivity"
        android:exported="true"
        android:theme="@style/Theme.WindowBlur"
        />
    
    //Activity使用的主题
    <style name="Theme.WindowBlur" parent="Theme.MaterialComponents.Dialog">
        <item name="android:windowIsTranslucent">true</item>
    </style>
    
    //Activity使用的布局
    activity_blur.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="300dp"
        android:layout_height="300dp"
        tools:context="com.example.windowblur.BlurActivity"
        android:layout_gravity="center"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textSize="32sp"
            android:textColor="#000000"
            android:padding="32dp"
            android:text="铜镜映无邪"
            android:textStyle="bold"
            />
    </RelativeLayout>
    
    //支持窗口模糊 和 不支持窗口模糊 将要使用的窗口背景drawable
    //window_background_with_blur.xml
    //半透明红色
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="#32FF0000" />
        <corners android:radius="16dp" />
    </shape>
    //window_background_no_blur.xml
    //半透明绿色
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="#3200FF00" />
        <corners android:radius="16dp" />
    </shape>
    
    class BlurActivity : AppCompatActivity() {
        private val mBackgroundBlurRadius = 100
        private var mBackgroundDrawableWithBlur: Drawable? = null
        private var mBackgroundDrawableNoBlur: Drawable? = null
    
        private val mBlurBehindRadius = 20
        private val mDimAmountWithBlur = 0.1f
        private val mDimAmountNoBlur = 0.6f
    
        private val mCrossWindowBlurEnabledListener: Consumer<Boolean> = Consumer<Boolean> { enabled ->
            Log.i(TAG_TRACK, "mCrossWindowBlurEnabledListener. enabled:$enabled")
            window.setBackgroundDrawable(
                if (enabled) mBackgroundDrawableWithBlur else mBackgroundDrawableNoBlur
            )
            window.setDimAmount(if (enabled) mDimAmountWithBlur else mDimAmountNoBlur)
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_blur)
            mBackgroundDrawableWithBlur = resources.getDrawable(
                R.drawable.window_background_with_blur
            )
            mBackgroundDrawableNoBlur = resources.getDrawable(
                R.drawable.window_background_no_blur
            )
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                window.addFlags(
                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND
                )
                //window.attributes.blurBehindRadius 用于设置Activity的窗口后面所有内容的模糊
                window.attributes.blurBehindRadius = mBlurBehindRadius;
                //window.setBackgroundBlurRadius 用于设置Activity的窗口自身的背景模糊
                window.setBackgroundBlurRadius(mBackgroundBlurRadius)
                window.decorView.addOnAttachStateChangeListener(
                    object : View.OnAttachStateChangeListener {
                        override fun onViewAttachedToWindow(v: View?) {
                            Log.i(TAG_TRACK, "onViewAttachedToWindow. addCrossWindowBlurEnabledListener.")
                            //添加监听
                            windowManager.addCrossWindowBlurEnabledListener(
                                mCrossWindowBlurEnabledListener
                            )
                        }
    
                        override fun onViewDetachedFromWindow(v: View?) {
                            Log.i(TAG_TRACK, "onViewDetachedFromWindow. removeCrossWindowBlurEnabledListener.")
                            //移除监听
                            windowManager.removeCrossWindowBlurEnabledListener(
                                mCrossWindowBlurEnabledListener
                            )
                        }
                    })
            }
            window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        }
    }
    
  3. 红米手机实际运行截图 Screenshot_2023-03-10-18-08-21-661_com.example.jet2022.jpg