当前位置: 首页 > news >正文

Android 编写高斯模糊功能

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;    // 更新间隔 msprivate 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}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();// 注册 PreDraw 监听preDrawListener = () -> {long now = System.currentTimeMillis();if (now - lastUpdateTime >= updateInterval) {lastUpdateTime = now;blurAndInvalidate();}return true;};getViewTreeObserver().addOnPreDrawListener(preDrawListener);}@Overrideprotected 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() {// 默认用父容器,或者用用户手动设置的 viewView 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 缩放绘制到 bitmapbitmapCanvas.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();}@Overrideprotected 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.blurviewimport 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: Floatprivate var downsampleFactor: Intprivate var updateInterval: Longprivate var bitmapBuffer: Bitmap? = nullprivate var bitmapCanvas: Canvas? = nullprivate val paint = Paint(Paint.ANTI_ALIAS_FLAG)// Android 12- 使用 RenderScriptprivate var rs: android.renderscript.RenderScript? = nullprivate var instBlur: android.renderscript.ScriptIntrinsicBlur? = nullprivate var allocIn: android.renderscript.Allocation? = nullprivate var allocOut: android.renderscript.Allocation? = nullprivate var preDrawListener: ViewTreeObserver.OnPreDrawListener? = nullprivate var lastUpdateTime = 0L// ✨ 可手动指定模糊源private var blurredView: View? = nullinit {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 = nowblurAndInvalidate()}true}viewTreeObserver.addOnPreDrawListener(preDrawListener)}override fun onDetachedFromWindow() {super.onDetachedFromWindow()preDrawListener?.let { viewTreeObserver.removeOnPreDrawListener(it) }bitmapBuffer?.recycle()bitmapBuffer = nullrs?.destroy()rs = null}/** ✨ 外部调用,设置需要模糊的目标 View */fun setBlurredView(view: View?) {blurredView = view}/** 执行模糊并重绘自己 */private fun blurAndInvalidate() {val target = blurredView ?: parent as? View ?: returnval width = target.widthval height = target.heightif (width == 0 || height == 0) returnval bw = width / downsampleFactorval bh = height / downsampleFactorif (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+ 使用 RenderEffectsetRenderEffect(RenderEffect.createBlurEffect(blurRadius, blurRadius, Shader.TileMode.CLAMP))} else {// Android 12- 使用 RenderScriptbitmapBuffer?.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.BlurViewandroid:id="@+id/blurView"android:layout_width="match_parent"android:layout_height="match_parent" /><!-- 遮罩层,调节背景亮度,仿iOS的高斯模糊 --><Viewandroid:id="@+id/dimOverlay"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#66000000" />  <!-- 半透明黑色 --><!-- 下面是你具体的UI代码 -->
</RelativeLayout>

以下是最后一点代码,具体怎么引用实现

// 配置 BlurViewBlurView blurView = view.findViewById(R.id.blurView);if (getActivity() != null) {View decorView = getActivity().getWindow().getDecorView();blurView.setBlurredView(decorView); // 指定模糊背景为整个 Activity}

太久没写博客,有什么问题见谅
我写这一篇主打一个直接复制粘贴
注:java里面没有对Android12以上进行处理,如你的版本是12及以上,请参考kotiln的实现

http://www.dtcms.com/a/356071.html

相关文章:

  • Github上传READ.md后出现不识别换行符的问题
  • Shell编程入门到实战:从基础语法到自动化脚本
  • 网络是怎样连接的,笔记整理
  • C语言知识点补充(链表和队列)
  • 8.变量和数据类型
  • 浏览器访问 ASP.NET Core wwwroot 目录下静态资源的底层实现
  • 多线程 线程池 并发
  • 机器视觉学习-day08-图像缩放
  • MBA/EMBA毕业论文写作总结
  • 第20章|轻松实现远程控制
  • NumPy 2.x 完全指南【三十二】通用函数(ufunc)之数学运算函数
  • 面试tips--JVM(1)--对象分配内存的方式TLAB
  • CTFshow系列——命令执行web61-68
  • C++之多态篇
  • 君正T31学习(四)- MT7682+VLC出图
  • 【python】python进阶——as关键字
  • 程序代码篇---类
  • SpringCloud Alibaba Nacos 注册中心/配置中心
  • SpringBoot 配置文件在运维开发中的应用
  • 基于springboot的商业店铺租赁系统
  • 在 Vue 前端(Vue2/Vue3 通用)载入 JSON 格式的动图
  • 校园文化活动管理系统设计与实现(代码+数据库+LW)
  • web前端知识——第一阶段
  • 【buildroot】【1. Buildroot版本与Linux内核调试对应关系】
  • 基于SpringBoot的旅游景点推荐系统【2026最新】
  • 域名所有权变更,需要重新备案吗
  • Day16_【机器学习分类】
  • 软磁材料与硬磁材料
  • MTK Linux DRM分析(十九)- KMS drm_framebuffer.c
  • LeetCode 141.环形链表