1. 这篇文章主要是写的Androidsupper库的高斯模糊,主打一个直接复制粘贴可以直接使用,如需要Android12以后,需要自行百度进行适配
2. 首先是用到的一些自定义属性,在你的xml下,value文件夹attr文件里面添加以下自定义属性
一、
<declare-styleable name="BlurView">
<attr name="blurRadius" format="integer" />
<attr name="downsampleFactor" format="integer" />
<attr name="updateInterval" format="integer" />
</declare-styleable>
1. blurRadius —— 模糊半径
定义:控制高斯模糊的模糊程度,数值越大,模糊越“散”,看起来更模糊。
表现:
小值(比如 5):模糊轻微,背景还能依稀看到。
大值(比如 20):模糊强烈,背景几乎看不清。
影响性能:半径越大,模糊计算量越多,性能开销更大。
2. downsampleFactor —— 降采样倍数
定义:在做模糊之前,先把画面缩小(降采样),再做模糊,最后再放大到原来的大小。
作用:
降低需要计算的像素数量,提高模糊运算速度。
同时也会让模糊看起来更“糊”,因为缩小再放大损失了细节。
举例:
downsampleFactor = 1 → 不缩小,清晰但耗性能。
downsampleFactor = 4 → 缩小到 1/4 再模糊,性能大幅提升,但细节损失明显。
3、 updateInterval 这个是更新间隔,根据需求自行调整
二、BlurView的详细代码,我这里贴一份java的和一份kotlin的,kotiln的事最新的版本直接进行引用
public class BlurView extends FrameLayout {
private int blurRadius; // 模糊半径
private int downsampleFactor; // 降采样倍数
private long updateInterval; // 更新间隔 ms
private Bitmap bitmapBuffer;
private Canvas bitmapCanvas;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RenderScript rs;
private ScriptIntrinsicBlur instBlur;
private Allocation allocIn, allocOut;
private ViewTreeObserver.OnPreDrawListener preDrawListener;
private long lastUpdateTime = 0;
// ✨ 新增:可以手动指定模糊源
private View blurredView;
public BlurView(Context c) {
this(c, null);
}
public BlurView(Context c, AttributeSet attrs) {
this(c, attrs, 0);
}
public BlurView(Context c, AttributeSet attrs, int defStyle) {
super(c, attrs, defStyle);
// 读取属性
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.BlurView);
blurRadius = a.getInt(R.styleable.BlurView_blurRadius, 15);
downsampleFactor = a.getInt(R.styleable.BlurView_downsampleFactor, 4);
updateInterval = a.getInt(R.styleable.BlurView_updateInterval, 100);
a.recycle();
// 初始化 RenderScript 模糊
rs = RenderScript.create(c);
instBlur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
instBlur.setRadius(blurRadius);
setWillNotDraw(false); // 允许 onDraw
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// 注册 PreDraw 监听
preDrawListener = () -> {
long now = System.currentTimeMillis();
if (now - lastUpdateTime >= updateInterval) {
lastUpdateTime = now;
blurAndInvalidate();
}
return true;
};
getViewTreeObserver().addOnPreDrawListener(preDrawListener);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// 清理
getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
if (bitmapBuffer != null) {
bitmapBuffer.recycle();
bitmapBuffer = null;
}
if (rs != null) rs.destroy();
}
/**
* ✨ 新增:外部调用,设置需要模糊的目标 View
*/
public void setBlurredView(View view) {
this.blurredView = view;
}
/**
* 执行模糊并重绘自己
*/
private void blurAndInvalidate() {
// 默认用父容器,或者用用户手动设置的 view
View target = blurredView != null ? blurredView : (View) getParent();
if (target == null) return;
int width = target.getWidth();
int height = target.getHeight();
if (width == 0 || height == 0) return;
int bw = width / downsampleFactor;
int bh = height / downsampleFactor;
// 初始化缓存
if (bitmapBuffer == null ||
bitmapBuffer.getWidth() != bw ||
bitmapBuffer.getHeight() != bh) {
bitmapBuffer = Bitmap.createBitmap(bw, bh, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmapBuffer);
}
// 将 target 缩放绘制到 bitmap
bitmapCanvas.save();
bitmapCanvas.scale(1f / downsampleFactor, 1f / downsampleFactor);
target.draw(bitmapCanvas);
bitmapCanvas.restore();
if (allocIn != null) allocIn.destroy();
if (allocOut != null) allocOut.destroy();
allocIn = Allocation.createFromBitmap(rs, bitmapBuffer);
allocOut = Allocation.createTyped(rs, allocIn.getType());
instBlur.setInput(allocIn);
instBlur.forEach(allocOut);
allocOut.copyTo(bitmapBuffer);
// 触发重绘
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bitmapBuffer != null) {
// 绘制放大回屏幕
canvas.save();
canvas.scale(downsampleFactor, downsampleFactor);
canvas.drawBitmap(bitmapBuffer, 0, 0, paint);
canvas.restore();
}
}
}
以下是kotiln的代码
package com.example.blurview
import android.content.Context
import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import android.view.*
import android.widget.FrameLayout
import androidx.annotation.RequiresApi
import androidx.core.view.ViewCompat
@Suppress("DEPRECATION")
class BlurView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : FrameLayout(context, attrs, defStyle) {
private var blurRadius: Float
private var downsampleFactor: Int
private var updateInterval: Long
private var bitmapBuffer: Bitmap? = null
private var bitmapCanvas: Canvas? = null
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
// Android 12- 使用 RenderScript
private var rs: android.renderscript.RenderScript? = null
private var instBlur: android.renderscript.ScriptIntrinsicBlur? = null
private var allocIn: android.renderscript.Allocation? = null
private var allocOut: android.renderscript.Allocation? = null
private var preDrawListener: ViewTreeObserver.OnPreDrawListener? = null
private var lastUpdateTime = 0L
// ✨ 可手动指定模糊源
private var blurredView: View? = null
init {
val a = context.obtainStyledAttributes(attrs, R.styleable.BlurView)
blurRadius = a.getInt(R.styleable.BlurView_blurRadius, 15).toFloat()
downsampleFactor = a.getInt(R.styleable.BlurView_downsampleFactor, 4)
updateInterval = a.getInt(R.styleable.BlurView_updateInterval, 100).toLong()
a.recycle()
// 初始化 RenderScript (仅 Android 12 以下)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
rs = android.renderscript.RenderScript.create(context)
instBlur = android.renderscript.ScriptIntrinsicBlur.create(
rs,
android.renderscript.Element.U8_4(rs)
).apply {
radius = blurRadius
}
}
setWillNotDraw(false)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
preDrawListener = ViewTreeObserver.OnPreDrawListener {
val now = System.currentTimeMillis()
if (now - lastUpdateTime >= updateInterval) {
lastUpdateTime = now
blurAndInvalidate()
}
true
}
viewTreeObserver.addOnPreDrawListener(preDrawListener)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
preDrawListener?.let { viewTreeObserver.removeOnPreDrawListener(it) }
bitmapBuffer?.recycle()
bitmapBuffer = null
rs?.destroy()
rs = null
}
/** ✨ 外部调用,设置需要模糊的目标 View */
fun setBlurredView(view: View?) {
blurredView = view
}
/** 执行模糊并重绘自己 */
private fun blurAndInvalidate() {
val target = blurredView ?: parent as? View ?: return
val width = target.width
val height = target.height
if (width == 0 || height == 0) return
val bw = width / downsampleFactor
val bh = height / downsampleFactor
if (bitmapBuffer == null || bitmapBuffer?.width != bw || bitmapBuffer?.height != bh) {
bitmapBuffer = Bitmap.createBitmap(bw, bh, Bitmap.Config.ARGB_8888)
bitmapCanvas = Canvas(bitmapBuffer!!)
}
bitmapCanvas?.apply {
save()
scale(1f / downsampleFactor, 1f / downsampleFactor)
target.draw(this)
restore()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Android 12+ 使用 RenderEffect
setRenderEffect(RenderEffect.createBlurEffect(blurRadius, blurRadius, Shader.TileMode.CLAMP))
} else {
// Android 12- 使用 RenderScript
bitmapBuffer?.let { bmp ->
allocIn?.destroy()
allocOut?.destroy()
allocIn = android.renderscript.Allocation.createFromBitmap(rs, bmp)
allocOut = android.renderscript.Allocation.createTyped(rs, allocIn!!.type)
instBlur?.setInput(allocIn)
instBlur?.forEach(allocOut)
allocOut?.copyTo(bmp)
}
}
invalidate()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
bitmapBuffer?.let { bmp ->
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
canvas.save()
canvas.scale(downsampleFactor.toFloat(), downsampleFactor.toFloat())
canvas.drawBitmap(bmp, 0f, 0f, paint)
canvas.restore()
}
}
}
}
还有需要再build文件内需要配置属性
在android下defaultConfig内添加以下两个属性:
renderscriptTargetApi 21
renderscriptSupportModeEnabled true
三、如何使用
上面已经写了相关的文件和配置,下面是如何在xml文件中如何使用,以及一些注意事项:
先是xml怎么用:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000">
<!-- 2. 动态模糊遮罩层 -->
<com.cars.mobile.view.BlurView
android:id="@+id/blurView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- 遮罩层,调节背景亮度,仿iOS的高斯模糊 -->
<View
android:id="@+id/dimOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#66000000" /> <!-- 半透明黑色 -->
<!-- 下面是你具体的UI代码 -->
</RelativeLayout>
以下是最后一点代码,具体怎么引用实现
// 配置 BlurView
BlurView blurView = view.findViewById(R.id.blurView);
if (getActivity() != null) {
View decorView = getActivity().getWindow().getDecorView();
blurView.setBlurredView(decorView); // 指定模糊背景为整个 Activity
}
太久没写博客,有什么问题见谅
我写这一篇主打一个直接复制粘贴
注:java里面没有对Android12以上进行处理,如你的版本是12及以上,请参考kotiln的实现