• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

陈文管的博客

分享有价值的内容

  • Android
  • Affiliate
  • SEO
  • 前后端
  • 网站建设
  • 自动化
  • 开发资源
  • 关于

Android 布局高斯模糊处理

2025年11月23日发布 | 最近更新于 2025年11月23日

前面写了不规则图形高斯模糊控件实现,现在给出不通过截图实现的布局高斯模糊处理实现,只对布局做高斯模糊效果,不耗费性能。(注意:如果使用此方法出现崩溃,说明运行的Android SDK版本不支持)

实现效果示例如下,中心偏右的地方就是高斯模糊覆盖蓝色圆形图标的效果,可以根据实际需求调整模糊程度。

Android布局高斯模糊处理实现

直接给出Java和Kotlin的实现代码。

一、Java代码实现

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.util.Log;
import android.view.View;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;


public class GaussianBlur {
    private static final String TAG = "GaussianBlur";
    public static final int ALL_SAME = 0;
    public static final int TOP_DIFFERENT = 1;
    public static final int BOTTOM_DIFFERENT = 2;
    public static final int LEFT_TOP_RIGHT_ANGLE = 3; // 仅左上角为直角

    /**
     * 为 View 设置高斯模糊背景
     * @param rootViewGroup 根视图组用于获取模糊源
     * @param targetView 需要设置模糊背景的目标视图
     * @param radius view四个角的圆角半径
     * @param blurRadius 模糊半径 (0-200) 默认值 60 超过200会被重置为200
     * @param cornerType 圆角类型 [ALL_SAME], [TOP_DIFFERENT], [BOTTOM_DIFFERENT]
     * @param resId 背景资源ID,默认值为 R.drawable.layer_bg
     */
    public static void gaussianBlurBackground(
            View rootViewGroup,
            View targetView,
            int radius,
            int blurRadius,
            int cornerType,
            int resId) {
        Drawable blurDrawable = createBlurDrawable(rootViewGroup, radius, cornerType, blurRadius);
        Drawable originDrawable = (resId == -1) ?
                createSolidRoundDrawable(radius, targetView.getContext()) : getDrawable(targetView.getContext(), resId);
        Drawable background = createLayerDrawable(blurDrawable, originDrawable);

        targetView.setBackground(background);
        targetView.postInvalidate();
    }

    // 重载方法,提供默认参数
    public static void gaussianBlurBackground(
            View rootViewGroup,
            View targetView,
            int radius) {
        gaussianBlurBackground(rootViewGroup, targetView, radius, 60, 0, -1);
    }

    public static void gaussianBlurBackground(
            View rootViewGroup,
            View targetView,
            int radius,
            int blurRadius) {
        gaussianBlurBackground(rootViewGroup, targetView, radius, blurRadius, 0, -1);
    }

    public static void gaussianBlurBackground(
            View rootViewGroup,
            View targetView,
            int radius,
            int blurRadius,
            int cornerType) {
        gaussianBlurBackground(rootViewGroup, targetView, radius, blurRadius, cornerType, -1);
    }

    public static Drawable getDrawable(Context context, int resId) {
        if (resId == 0) {
            Log.e("DrawableUtils", "error drawableId = 0");
            return null;
        }
        return ResourcesCompat.getDrawable(context.getResources(), resId, context.getTheme());
    }

    /**
     * 创建纯色圆角Drawable
     * @param radius 圆角半径(单位:像素)
     * @param context 上下文
     */
    public static Drawable createSolidRoundDrawable(int radius, Context context) {
        GradientDrawable drawable = new GradientDrawable();
        drawable.setShape(GradientDrawable.RECTANGLE);
        // 注意:需要替换为你的颜色资源
        drawable.setColor(ContextCompat.getColor(context, R.color.color_blur_bg));
        drawable.setCornerRadius(radius);
        return drawable;
    }

    /**
     * 创建模糊Drawable
     * @param rootViewGroup 根视图组
     * @param radius 圆角半径
     * @param cornerType 圆角设置类型
     * @param blurRadius 模糊半径
     * @return 模糊Drawable
     */
    private static Drawable createBlurDrawable(
            View rootViewGroup,
            int radius,
            int cornerType,
            int blurRadius) {
        Object viewParent = rootViewGroup.getParent();
        if (viewParent == null) {
            Log.w(TAG, "View parent is null");
            return null;
        }

        try {
            java.lang.reflect.Method blurMethod = viewParent.getClass().getDeclaredMethod("createBackgroundBlurDrawable");
            blurMethod.setAccessible(true);
            Drawable blurDrawable = (Drawable) blurMethod.invoke(viewParent);

            if (blurDrawable != null) {
                setBlurRadius(blurDrawable, blurRadius);
                setCornerRadius(blurDrawable, cornerType, radius);
            }
            return blurDrawable;
        } catch (Exception e) {
            Log.e(TAG, "Reflection failed: ", e);
            return null;
        }
    }

    /**
     * 设置模糊半径
     */
    private static void setBlurRadius(Drawable drawable, int radius) {
        try {
            int clampedRadius = Math.max(0, Math.min(radius, 200));
            java.lang.reflect.Method method = drawable.getClass().getDeclaredMethod("setBlurRadius", int.class);
            method.setAccessible(true);
            method.invoke(drawable, clampedRadius);
        } catch (Exception e) {
            Log.w(TAG, "setBlurRadius failed: " + e.getMessage());
        }
    }

    /**
     * 设置圆角半径
     */
    private static void setCornerRadius(Drawable drawable, int cornerType, int radius) {
        try {
            int dimen = radius;
            Log.i(TAG, "setCornerRadius dimen: " + dimen + "  cornerType: " + cornerType);

            switch (cornerType) {
                case ALL_SAME:
                    java.lang.reflect.Method method1 = drawable.getClass().getDeclaredMethod("setCornerRadius", float.class);
                    method1.invoke(drawable, (float) dimen);
                    break;

                case LEFT_TOP_RIGHT_ANGLE:
                    java.lang.reflect.Method method2 = drawable.getClass().getDeclaredMethod(
                            "setCornerRadius",
                            float.class, float.class, float.class, float.class);
                    method2.invoke(drawable, 0f, (float) dimen, (float) dimen, (float) dimen);
                    break;

                case TOP_DIFFERENT:
                    java.lang.reflect.Method method3 = drawable.getClass().getDeclaredMethod(
                            "setCornerRadius",
                            float.class, float.class, float.class, float.class);
                    method3.invoke(drawable, (float) dimen, (float) dimen, 0f, 0f);
                    break;

                case BOTTOM_DIFFERENT:
                    java.lang.reflect.Method method4 = drawable.getClass().getDeclaredMethod(
                            "setCornerRadius",
                            float.class, float.class, float.class, float.class);
                    method4.invoke(drawable, 0f, 0f, (float) dimen, (float) dimen);
                    break;
            }
        } catch (Exception e) {
            Log.e(TAG, "setCornerRadius failed:", e);
        }
    }

    /**
     * 创建图层Drawable
     */
    private static Drawable createLayerDrawable(Drawable blurDrawable, Drawable overlayDrawable) {
        if (blurDrawable != null && overlayDrawable != null) {
            return new LayerDrawable(new Drawable[]{blurDrawable, overlayDrawable});
        } else if (blurDrawable != null) {
            return blurDrawable;
        } else if (overlayDrawable != null) {
            return overlayDrawable;
        } else {
            return null;
        }
    }
}

二、Kotlin代码实现

import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
import android.util.Log
import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat


object GaussianBlur {
    private const val TAG = "GaussianBlur"
    const val ALL_SAME = 0
    const val TOP_DIFFERENT = 1
    const val BOTTOM_DIFFERENT = 2
    const val LEFT_TOP_RIGHT_ANGLE = 3 // 仅左上角为直角

    /**
     * 为 View 设置高斯模糊背景
     * @param rootViewGroup 根视图组用于获取模糊源
     * @param targetView 需要设置模糊背景的目标视图
     * @param radius view四个角的圆角半径
     * @param blurRadius 模糊半径 (0-200) 默认值 60 超过200会被重置为200
     * @param cornerType 圆角类型 [ALL_SAME], [TOP_DIFFERENT], [BOTTOM_DIFFERENT]
     * @param resId 背景资源ID,默认值为 R.drawable.layer_bg
     */
    @JvmOverloads
    fun gaussianBlurBackground(
        rootViewGroup: View,
        targetView: View,
        radius: Int,
        blurRadius: Int = 60,
        cornerType: Int = ALL_SAME,
        resId: Int = -1
    ) {
        val blurDrawable = createBlurDrawable(rootViewGroup, radius, cornerType, blurRadius)
        val originDrawable = if (resId == -1)
            createSolidRoundDrawable(radius, targetView.context)
        else
            getDrawable(targetView.context, resId)
        val background = createLayerDrawable(blurDrawable, originDrawable)

        targetView.background = background
        targetView.postInvalidate()
    }

    fun getDrawable(context: Context, resId: Int): Drawable? {
        if (resId == 0) {
            Log.e("DrawableUtils", "error drawableId = 0")
            return null
        }
        return ResourcesCompat.getDrawable(context.resources, resId, context.theme)
    }

    /**
     * 创建纯色圆角Drawable
     * @param radius 圆角半径(单位:像素)
     * @param context 上下文
     */
    fun createSolidRoundDrawable(radius: Int, context: Context): Drawable {
        val drawable = GradientDrawable()
        drawable.shape = GradientDrawable.RECTANGLE
        // 注意:需要替换为你的颜色资源
        drawable.setColor(ContextCompat.getColor(context, R.color.color_blur_bg))
        drawable.cornerRadius = radius.toFloat()
        return drawable
    }

    /**
     * 创建模糊Drawable
     * @param rootViewGroup 根视图组
     * @param radius 圆角半径
     * @param cornerType 圆角设置类型
     * @param blurRadius 模糊半径
     * @return 模糊Drawable
     */
    private fun createBlurDrawable(
        rootViewGroup: View,
        radius: Int,
        cornerType: Int,
        blurRadius: Int
    ): Drawable? {
        val viewParent = rootViewGroup.parent ?: run {
            Log.w(TAG, "View parent is null")
            return null
        }

        return try {
            val blurMethod = viewParent.javaClass.getDeclaredMethod("createBackgroundBlurDrawable")
            blurMethod.isAccessible = true
            val blurDrawable = blurMethod.invoke(viewParent) as? Drawable

            blurDrawable?.let {
                setBlurRadius(it, blurRadius)
                setCornerRadius(it, cornerType, radius)
            }
            blurDrawable
        } catch (e: Exception) {
            Log.e(TAG, "Reflection failed: ", e)
            null
        }
    }

    /**
     * 设置模糊半径
     */
    private fun setBlurRadius(drawable: Drawable, radius: Int) {
        try {
            val clampedRadius = radius.coerceIn(0, 200)
            val method = drawable.javaClass.getDeclaredMethod("setBlurRadius", Int::class.javaPrimitiveType)
            method.isAccessible = true
            method.invoke(drawable, clampedRadius)
        } catch (e: Exception) {
            Log.w(TAG, "setBlurRadius failed: ${e.message}")
        }
    }

    /**
     * 设置圆角半径
     */
    private fun setCornerRadius(drawable: Drawable, cornerType: Int, radius: Int) {
        try {
            val dimen = radius
            Log.i(TAG, "setCornerRadius dimen: $dimen  cornerType: $cornerType")

            when (cornerType) {
                ALL_SAME -> {
                    val method = drawable.javaClass.getDeclaredMethod("setCornerRadius", Float::class.javaPrimitiveType)
                    method.invoke(drawable, dimen.toFloat())
                }

                LEFT_TOP_RIGHT_ANGLE -> {
                    val method = drawable.javaClass.getDeclaredMethod(
                        "setCornerRadius",
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType
                    )
                    method.invoke(drawable, 0f, dimen.toFloat(), dimen.toFloat(), dimen.toFloat())
                }

                TOP_DIFFERENT -> {
                    val method = drawable.javaClass.getDeclaredMethod(
                        "setCornerRadius",
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType
                    )
                    method.invoke(drawable, dimen.toFloat(), dimen.toFloat(), 0f, 0f)
                }

                BOTTOM_DIFFERENT -> {
                    val method = drawable.javaClass.getDeclaredMethod(
                        "setCornerRadius",
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType,
                        Float::class.javaPrimitiveType
                    )
                    method.invoke(drawable, 0f, 0f, dimen.toFloat(), dimen.toFloat())
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "setCornerRadius failed:", e)
        }
    }

    /**
     * 创建图层Drawable
     */
    private fun createLayerDrawable(blurDrawable: Drawable?, overlayDrawable: Drawable?): Drawable? {
        return when {
            blurDrawable != null && overlayDrawable != null -> LayerDrawable(arrayOf(blurDrawable, overlayDrawable))
            blurDrawable != null -> blurDrawable
            overlayDrawable != null -> overlayDrawable
            else -> null
        }
    }
}

三、调用示例

rootView 传根布局对象,blurView 传需要高斯模糊的布局对象,如果需要让布局有圆角就修改第三个参数,0就是直角:

GaussianBlur.gaussianBlurBackground(rootView, blurView, 0, 60, R.drawable.layer_bg)

layer_bg 的配置如下,配置成自己需要的带透明度的颜色:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
  <solid android:color="@color/color_white_50" />
</shape>

扩展阅读:

  • Android不规则图形高斯模糊控件实现
  • Android 航线剖面图自定义控件绘制实现
  • Android 自定义棱形样式进度条控件
  • Android 弧形 RecyclerView 实现(Kotlin)
  • 美图手机音乐Widget动画实现
  • Android 心率动画自定义控件实现
  • Android 卡片旋转切换动效实现详解
  • Android 残影数字动画实现详解
  • Android 自定义菱形横向滑动指示器控件
  • Android 航线缩略图简易绘制实现
  • Android PDF文件浏览及目录显示交互实现
博客公众号

微信公众号

转载请注明出处:陈文管的博客 – Android 布局高斯模糊处理

发表回复 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

4 × 1 =

文章目录

  • 一、Java代码实现
  • 二、Kotlin代码实现
  • 三、调用示例
博客公众号

闽ICP备18001825号-1 · Copyright © 2025 · Powered by chenwenguan.com