Android12窗口模糊(二)高斯模糊API源码解析

news2024/11/24 3:24:40

前言

在 Android 12 中,提供了一些用于实现窗口模糊处理效果(例如背景模糊处理和模糊处理后方屏幕)的公共 API。窗口模糊处理或跨窗口模糊处理用于模糊处理给定窗口后方的屏幕。
有两种窗口模糊处理方式,可用于实现不同的视觉效果:

  • 背景模糊处理(Background blur):可用于创建具有模糊背景的窗口,创造出磨砂玻璃效果,模糊区域是窗口。

  • 模糊处理后方屏幕(Blur behind):可用于模糊处理(对话框)窗口后方的整个屏幕,创造出景深效果,模糊区域是整个屏幕。

这两种效果可以单独使用,也可以组合使用,如下图所示:

上面的三张效果图是谷歌官方所提供的效果图:
在这里插入图片描述
(a)仅背景模糊处理(Background blur)
(b)仅模糊处理后方屏幕(Blur behind)
(c)背景模糊处理和模糊处理后方屏幕(Background blur)+(Blur behind)

上一篇我们已经讲述了Android12如何使用原生API实现高斯模糊效果,本篇文章我们将会结合源码具体分析原生API实现高斯模糊效果的底层逻辑。

一、API对应的源码

1、PhoneWindow的setBackgroundBlurRadius方法如下所示:

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    @Override
    public final void setBackgroundBlurRadius(int blurRadius) {
        super.setBackgroundBlurRadius(blurRadius);
        if (CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED) {
            if (mBackgroundBlurRadius != Math.max(blurRadius, 0)) {
                mBackgroundBlurRadius = Math.max(blurRadius, 0);
                mDecor.setBackgroundBlurRadius(mBackgroundBlurRadius);
            }
        }
    }
}

setBackgroundBlurRadius首先判断用户有没有设置blurRadius,如果设置了会继续调用DecorView的setBackgroundBlurRadius方法。

2、DecorView的setBackgroundBlurRadius方法如下所示:

frameworks/base/core/java/com/android/internal/policy/DecorView.java

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
    void setBackgroundBlurRadius(int blurRadius) {
        mOriginalBackgroundBlurRadius = blurRadius;
        if (blurRadius > 0) {
            if (mCrossWindowBlurEnabledListener == null) {
                mCrossWindowBlurEnabledListener = enabled -> {
                    mCrossWindowBlurEnabled = enabled;
                    updateBackgroundBlurRadius();
                };
                getContext().getSystemService(WindowManager.class)
                        .addCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
                getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
            } else {
            	//更新高斯模糊背景的高斯半径
                updateBackgroundBlurRadius();
            }
        } else if (mCrossWindowBlurEnabledListener != null) {
            updateBackgroundBlurRadius();
            removeBackgroundBlurDrawable();
        }
    }
    
 }

DecorView的setBackgroundBlurRadius方法进行一些判断之后,会调用一个比较关键的方法updateBackgroundBlurRadius。

3、DecorView的updateBackgroundBlurRadius方法如下所示:

    //更新高斯模糊背景的高斯半径
    private void updateBackgroundBlurRadius() {
        //如果viewRootImpl为空直接返回
        if (getViewRootImpl() == null) return;

        //获取背景高斯模糊效果半径
        mBackgroundBlurRadius = mCrossWindowBlurEnabled && mWindow.isTranslucent()
                ? mOriginalBackgroundBlurRadius : 0;

        if (mBackgroundBlurDrawable == null && mBackgroundBlurRadius > 0) {
            //调用ViewRootImpl的方法创建高斯模糊Drawable文件
            mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
            updateBackgroundDrawable();
        }

        if (mBackgroundBlurDrawable != null) {
            mBackgroundBlurDrawable.setBlurRadius(mBackgroundBlurRadius);
        }
    }

updateBackgroundBlurRadius方法首先获取ViewRootImpl实例对象,如果为空直接返回;如果不为空则获取背景高斯模糊效果半径,当mCrossWindowBlurEnabled 为true且窗口时透明样式的时候,才会获取之前设置的高斯模糊效果半径,否则高斯模糊效果半径直接设置为0;然后会检测mBackgroundBlurDrawable是否为空,如果为空且获取的mBackgroundBlurRadius大于0,便会调用ViewRootImpl的createBackgroundBlurDrawable方法创建BackgroundBlurDrawable对象实例。

4、ViewRootImpl的createBackgroundBlurDrawable方法如下所示:

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
        AttachedSurfaceControl {
        
	private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator =
            new BackgroundBlurDrawable.Aggregator(this);

    public BackgroundBlurDrawable createBackgroundBlurDrawable() {
        return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext);
    }
 }

createBackgroundBlurDrawable方法仅仅是进一步调用mBlurRegionAggregator的createBackgroundBlurDrawable方法,mBlurRegionAggregator是BackgroundBlurDrawable的一个内部静态类。

5、Aggregator的createBackgroundBlurDrawable方法如下所示:

public final class BackgroundBlurDrawable extends Drawable {

    public static final class Aggregator {
    
        private final ViewRootImpl mViewRoot;
		...代码省略...
		
        public Aggregator(ViewRootImpl viewRoot) {
            mViewRoot = viewRoot;
        }

        /**
         * 使用默认背景模糊圆角半径创建一个模糊区域
         */
        public BackgroundBlurDrawable createBackgroundBlurDrawable(Context context) {
            BackgroundBlurDrawable drawable = new BackgroundBlurDrawable(this);
            drawable.setBlurRadius(context.getResources().getDimensionPixelSize(R.dimen.default_background_blur_radius));
            return drawable;
        }
		...代码省略...
    }
}    

Aggregator的createBackgroundBlurDrawable将自己作为参数,创建了一个继承自Drawable的BackgroundBlurDrawable对象实例,并设置模糊半径为dimens.xml文件中配置的default_background_blur_radius字段。

6、重新回到第3步DecorView的updateBackgroundBlurRadius方法中:

    //更新高斯模糊背景的高斯半径
    private void updateBackgroundBlurRadius() {
    	...代码省略...
        if (mBackgroundBlurDrawable == null && mBackgroundBlurRadius > 0) {
            mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
            //更新背景Drawable
            updateBackgroundDrawable();
        }

        if (mBackgroundBlurDrawable != null) {
            mBackgroundBlurDrawable.setBlurRadius(mBackgroundBlurRadius);
        }
    }

在调用createBackgroundBlurDrawable方法为mBackgroundBlurDrawable进行赋值之后,会继续调用DecorView的updateBackgroundDrawable方法来更新当前DecorView所对应的背景Drawable,最后再使用mBackgroundBlurRadius更新mBackgroundBlurDrawable的模糊圆角半径数值。

7、DecorView的updateBackgroundDrawable方法如下所示:

    private void updateBackgroundDrawable() {
        // Background insets can be null if super constructor calls setBackgroundDrawable.
        if (mBackgroundInsets == null) {
            mBackgroundInsets = Insets.NONE;
        }

        if (mBackgroundInsets.equals(mLastBackgroundInsets)
                && mBackgroundBlurDrawable == mLastBackgroundBlurDrawable
                && mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) {
            return;
        }

        Drawable destDrawable = mOriginalBackgroundDrawable;
        if (mBackgroundBlurDrawable != null) {
            //将新获取的类型为BackgroundBlurDrawable的mBackgroundBlurDrawable
            // 和原来类型为Drawable的mOriginalBackgroundDrawable合并成一个LayerDrawable实例对象
            destDrawable = new LayerDrawable(new Drawable[]{mBackgroundBlurDrawable,
                    mOriginalBackgroundDrawable});
        }

        if (destDrawable != null && !mBackgroundInsets.equals(Insets.NONE)) {
            //将当前类型为LayerDrawable的destDrawable再封装成InsetDrawable实例对象
            destDrawable = new InsetDrawable(destDrawable,
                    mBackgroundInsets.left, mBackgroundInsets.top,
                    mBackgroundInsets.right, mBackgroundInsets.bottom) {

                /**
                 * Return inner padding so we don't apply the padding again in
                 * {@link DecorView#drawableChanged()}
                 */
                @Override
                public boolean getPadding(Rect padding) {
                    return getDrawable().getPadding(padding);
                }
            };
        }
        //调用父类方法设置这个类的背景Drawable
        super.setBackgroundDrawable(destDrawable);

        mLastBackgroundInsets = mBackgroundInsets;
        mLastBackgroundBlurDrawable = mBackgroundBlurDrawable;
        mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/23367.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不小心清空了回收站怎么恢复,回收站删除的东西可以恢复吗

不小心清空了回收站怎么恢复?回收站是操作系统提供的一个非常实用的功能,专门为用户保存从电脑硬盘删除的各种数据,因而很多时候我们都会用到回收站,它能够保存各种数据,我们也能够在里面恢复自己想要的数据&#xff0…

Flutter组件--AppBar相关属性

AppBar介绍 AppBar是基于Material Design设计风格的应用栏,一般使用在Scaffold内部,作为顶部导航栏。 为什么需要AppBar 1、因为导航栏里面一般由左侧功能键(返回键、菜单键)、标题、右侧功能键组成,而AppBar里面内置…

django的使用步骤详细

一、安装django pip install django 二、创建django项目 放django文件的的文件路径上输入cmd进入终端输入下面的命令 django-admin startproject 项目名称 三、app的创建 进入创建好的项目里面输入一下的命令 python manage.py startapp app名称 四、注册app 五、编写U…

计算机视觉:基于Numpy的图像处理技术(二):图像主成分分析(PCA)

计算机视觉:基于Numpy的图像处理技术(二):图像主成分分析🏳️‍🌈 文章目录计算机视觉:基于Numpy的图像处理技术(二):图像主成分分析:rainbow_flag:图像主成分…

企业数据泄漏事件频发,如何防止企业数据泄漏?

2022年即将接近尾声,这一年受疫情和国际经济形势影响,各行各业都不太好过,同样互联网领域发展不平衡、规则不健全、秩序不合理等问题日益凸显,虽然互联网的快速发展为企业数字化转型提供了支撑,但是互联网发展进程中“…

Android App开发动画特效之利用滚动器实现平滑翻页(附源码和演示 简单易懂)

需要图片集请点赞关注收藏后评论区留言~~~ 一、利用滚动器实现平滑翻页 在日常生活中,平移动画比较常见,有时也被称为位移动画,左右翻页和上下滚动其实都用到了平移动画,譬如平滑翻书的动画效果,就是位移动画的一种应…

BHQ-3 amine,1661064-89-6可在430nm至730nm范围内猝灭所有普通荧光团

英文名称:BHQ-3 amine CAS:1661064-89-6 外观:深紫色粉末 分子式:C32H36N7 分子量:518.69 储存条件:-20C,避光避湿 结构式: 凯新生物产品简介:干燥的寡核苷酸在环境…

如今传统企业如何做数字化转型?

如今传统企业如何做数字化转型? 传统企业的数字化转型,也分为大型企业和中小企业,二者的侧重是十分不同的! 大型传统企业数字化转型的侧重点是—— 如何利用新一代信息技术,整合其现有技术和资源优势,在相…

MyBatis的缓存

目录 1.一级缓存 情况一 : 不同的SqlSession对应不同的一级缓存 情况二 : 同一个SqlSession但是查询条件不同 情况三 : 同一个SqlSession两次查询期间执行了任何一次增删改操作 情况四 : 同一个SqlSession两次查询期间手动清空了缓存 2.二级缓存 2.1二级缓存的相关配置 3.MyBa…

内网渗透神器CobaltStrike之会话管理(五)

CS之间派生会话 将CS1管理的会话派生至CS2中, 简单来说就是将CS1服务器的肉鸡送给CS2服务器 准备环境 主机描述Kali(192.168.47.134)CS TeamServer1Kali2(192.168.47.144)CS TeamServer2Windows7(192.168.47.133)CS客户端,攻击机Windows7(192.168.47.141)受害机操作步骤 首先…

详解:MySQL自增ID与UUID的优缺点及选择建议,MySQL有序uuid与自定义函数实现

文章目录1.自增ID的优缺点1.1 优点1.2 缺点1.3 不适合以自增ID主键作为主键的情况2.UUID作为主键2.1 介绍2.2 优点2.3 缺点3.有序UUID作为主键3.1 介绍3.2 演示使用3.2.1 前提知识3.2.1.1 数据类型 - binary3.2.1.2 函数 - hex()3.2.1.3 函数 - unhex()3.2.2 数据库层3.2.3 JAV…

web自动化测试(java+seleium)环境安装

目录0、应用1、linux安装1.1 安装chromium1.2 安装chromedriver1.3 安装xvfb2、java maven依赖selenium依赖3、入门案例0、应用 前一段时间,需要实现一个模拟页面操作的功能,去检测程序运行是否稳定,因此就用到了web自动化检测的功能。 1、实…

Centos8安装部署JumpServer堡垒机

1:安装支持在线安装和离线安装,我们选择在线安装一键部署。安装需要的环境要求。 OS/ArchArchitectureLinux KernelSoft Requirementlinux/amd64x86_64> 4.0wget curl tar gettext iptables pythonlinux/arm64aarch64> 4.0wget curl tar gettext …

highcharts 堆积图

参考 多坐标轴混合图 | JShare 使用 js资源 https://cdn.highcharts.com.cn/10.2.1/highcharts.js https://cdn.highcharts.com.cn/10.2.1/modules/exporting.js https://img.hcharts.cn/highcharts-plugins/highcharts-zh_CN.js 效果 js 引用 <script src"https…

【网页设计】期末大作业html+css(体育网站)--杜丹特篮球介绍8页 带报告

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 校园篮球网页设计 | 足球体育运动 | 体育游泳运动 | 兵乓球 | 网球 | 等网站的设计与制作 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&…

代码随想录刷题|LeetCode 343. 整数拆分 96.不同的二叉搜索树

目录 343. 整数拆分 思路 整数拆分 96.不同的二叉搜索树 思路 不同的二叉搜索树 343. 整数拆分 题目链接&#xff1a;力扣 思路 动态规划的题目虽然说是要先确定dp数组的含义&#xff0c;再确定递归公式&#xff0c;但是总感觉这两者是相辅相成的&#xff0c;是一起出来的&…

[附源码]java毕业设计校园飞毛腿系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【三维点云】2-三维点云表征

文章目录内容概要1 三维数据的获取方式及原理1.1 被动测量单目立体视觉双目立体视觉多目立体视觉1.2 主动测量结构光3D成像TOF 3D成像脉冲法相位法2 三维数据的获取原理立体视觉测量法相机成像模型小孔成像模型&#xff08;相机成像模型的理想情况&#xff09;单目立体视觉聚焦…

[附源码]计算机毕业设计JAVA基于web的球类体育馆预定系统

[附源码]计算机毕业设计JAVA基于web的球类体育馆预定系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; …

SPARKSQL3.0-SessionState构建源码剖析

一、介绍 Apache Spark 2.0引入了SparkSession&#xff0c;其目的是为用户提供了一个统一的切入点来使用Spark的各项功能&#xff0c;不再需要显式地创建SparkConf, SparkContext 以及 SQLContext&#xff0c;因为这些对象已经封装在SparkSession中。此外SparkSession允许用户…