前面写了不规则图形高斯模糊控件实现,现在给出不通过截图实现的布局高斯模糊处理实现,只对布局做高斯模糊效果,不耗费性能。(注意:如果使用此方法出现崩溃,说明运行的Android SDK版本不支持)
实现效果示例如下,中心偏右的地方就是高斯模糊覆盖蓝色圆形图标的效果,可以根据实际需求调整模糊程度。

直接给出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 布局高斯模糊处理
发表回复