Android学习笔记之ColorMatrix、图像处理

2024-06-13 03:18

本文主要是介绍Android学习笔记之ColorMatrix、图像处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

飞呀

    • 1.色彩矩阵
      • 1.1改变偏移量
      • 1.2改变颜色系数
    • 2.使用ColorMatrix来改变图片的色光属性
      • 2.1 色调
      • 2.2 饱和度
      • 2.3 亮度
      • 2.4 效果混合postConcat
      • 2.5 示例
    • 3.使用颜色矩阵来改变图片
      • 3.1几种图片颜色矩阵处理效果
        • 3.1.1 灰度效果
        • 3.1.2 图像颜色反转
        • 3.1.3 怀旧效果
        • 3.1.4 去色效果
        • 3.1.5 高饱和度
    • 4.像素点分析
      • 4.1常用图像像素点处理效果
        • 4.1.1 底片效果
        • 4.1.2 浮雕效果

1.色彩矩阵

  图片是由点阵和颜色值组成的,点阵是一个包含像素的举证,每个元素对应着图片的一个像素。当我知道颜色和矩阵有关时比较惊讶,大学时学的线性代数在这里用上了。
  在Android中处理图像的色彩效果的类是颜色矩阵ColorMatrix。颜色矩阵是一个4x5的数字矩阵。对于每个像素点,都有一个颜色分量矩阵用来保存颜色的RGBA值。
A = { a b c d e f g h i j k l m n o p q r s t } C = { R G B A 1 } A= \left\{ \begin{matrix} a & b & c & d & e\\ f & g & h & i & j \\ k & l & m & n & o \\ p & q & r & s & t \end{matrix} \right\} C= \left\{ \begin{matrix} R \\ G \\ B \\ A \\ 1 \end{matrix} \right\} A=afkpbglqchmrdinsejotC=RGBA1
  矩阵A是一个4x5的颜色矩阵,在Android中使用一维数组的形式来存储[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]。矩阵C是一个颜色矩阵分量。
  使用矩阵乘法运算AC来处理颜色分量矩阵,矩阵A、C,乘法运算过程,如下。
R = { R 1 G 1 B 1 A 1 } = A C { a b c d e f g h i j k l m n o p q r s t } { R G B A 1 } = { a R b G c B d A e f R g G h B i A j R k G l B m A n o R p G q B r A s t } = { R 1 G 1 B 1 A 1 } R =\left\{ \begin{matrix} R1\\G1 \\ B1 \\ A1 \end{matrix} \right\} =AC \\ \left\{ \begin{matrix} a & b & c & d & e\\ f & g & h & i & j \\ k & l & m & n & o \\ p & q & r & s & t \end{matrix} \right\} \left\{ \begin{matrix} R\\G \\ B \\ A \\1 \end{matrix} \right\} =\left\{ \begin{matrix} aR & bG & cB & dA & e\\ fR & gG & hB & iA & j \\ Rk & Gl & Bm & An & o \\ Rp & Gq & Br & As & t \end{matrix} \right\} =\left\{ \begin{matrix} R1\\G1 \\ B1 \\ A1 \end{matrix} \right\} R=R1G1B1A1=ACafkpbglqchmrdinsejotRGBA1=aRfRRkRpbGgGGlGqcBhBBmBrdAiAAnAsejot=R1G1B1A1
R1 = a x R + b x G + c x B + d x A + e;
G1 = f x R + g x G + h x B + i x A + j;
B1 = k x R + l x G + m x B + n x A +o;
A1 = p x R + q x G + r x B + s x A + t;
A = { a b c d e f g h i j k l m n o p q r s t } A= \left\{ \begin{matrix} a & b & c & d & e\\ f & g & h & i & j \\ k & l & m & n & o \\ p & q & r & s & t \end{matrix} \right\} A=afkpbglqchmrdinsejot

  • 第一行的abcde值用来决定新的颜色值中的R——红色
  • 第二行的fghij值用来决定新的颜色值中的G——绿色
  • 第三行的klmno值用来决定新的颜色值中的B——蓝色
  • 第四行的pqrst值用来决定新的颜色值中的A——透明色

第五列ejot值分别用来决定每个分量中的offset,即偏移量

R1 = a x R + b x G + c x B + d x A + e,令a=1,b、c、d、e都等于0,结果为R1 =R。构造一个矩阵,如下。
A = { 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 } A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A=10000100001000010000
  如果把这个矩阵代入R1=AC,R1=R。这个矩阵通常被用来作为初始颜色矩阵来使用,不会对原有颜色值进行任何变化。
  改变颜色的两种方法:一是直接改变颜色的offset,二是改变对应RGBA的系数。

1.1改变偏移量

A = { 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 } A = { 1 0 0 0 100 0 1 0 0 100 0 0 1 0 0 0 0 0 1 0 } A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 100\\ 0 & 1 & 0 & 0 & 100 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A=10000100001000010000A=100001000010000110010000
  红色、绿色分量增加了100,红绿混合会得到黄色,最后图片颜色偏黄。

1.2改变颜色系数

A = { 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 } A = { 1 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 0 0 1 0 } A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 \\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A= \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0\\ 0 & 2 & 0 & 0 & 0\\ 0 &0 & 1& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} A=10000100001000010000A=10000200001000010000
  改变的绿色,图片颜色偏绿,后面会有相应的展示。

2.使用ColorMatrix来改变图片的色光属性

2.1 色调

  setRotate(int axis, float degrees),axis使用0、1、2来代表R、G、B三种颜色。degrees处理的值。

        ColorMatrix hueMatrix = new ColorMatrix();hueMatrix.setRotate(0, hue);hueMatrix.setRotate(1, hue);hueMatrix.setRotate(2, hue);

2.2 饱和度

  setSaturation(float sat),当sat为0时,图片就变成黑白图片了。

        ColorMatrix saturationMatrix = new ColorMatrix();saturationMatrix.setSaturation(saturation);

2.3 亮度

  setScale(float rScale, float gScale, float bScale,float aScale),当三原色以相同比例进行混合时,就会显示出白色,系统正是使用这个原理来改变一个图像的亮度。当亮度为0时,图片就变为黑色了。

        ColorMatrix lumMatrix = new ColorMatrix();lumMatrix.setScale(lum, lum, lum, 1);

2.4 效果混合postConcat

  将上面三种ColorMatrix 叠加,需要通过ColorMatrix 的postConcat方法。

        ColorMatrix imageMatrix = new ColorMatrix();imageMatrix.postConcat(hueMatrix);imageMatrix.postConcat(saturationMatrix);imageMatrix.postConcat(lumMatrix);

2.5 示例

  通过三个seekbar来控制图片效果的变化。
seekbar的监听事件

//MID_VALUE =127        seekbar最大值255
// float mHue = 0;
// float mStauration = 1.0f;
// float mLum = 1.0f;	@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {int id = seekBar.getId();switch (id) {case R.id.sb_1:mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180;break;case R.id.sb_2:mStauration = progress * 1.0F / MID_VALUE;break;case R.id.sb_3:mLum = progress * 1.0F / MID_VALUE;break;}iv.setImageBitmap(handleImageEffect(bm, mHue, mStauration, mLum));}

设置图像矩阵的代码

    public Bitmap handleImageEffect(Bitmap bm,float hue,float saturation,float lum) {Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bmp);Paint paint = new Paint();ColorMatrix hueMatrix = new ColorMatrix();hueMatrix.setRotate(0, hue);hueMatrix.setRotate(1, hue);hueMatrix.setRotate(2, hue);ColorMatrix saturationMatrix = new ColorMatrix();saturationMatrix.setSaturation(saturation);ColorMatrix lumMatrix = new ColorMatrix();lumMatrix.setScale(lum, lum, lum, 1);ColorMatrix imageMatrix = new ColorMatrix();imageMatrix.postConcat(hueMatrix);imageMatrix.postConcat(saturationMatrix);imageMatrix.postConcat(lumMatrix);paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));canvas.drawBitmap(bm, 0, 0, paint);return bmp;}

  设置好颜色矩阵后,需要使用paint类的setColorFilter方法,将imageMatrix构造的ColorMatrixColorFilter对象传递进去。
  Android系统不允许直接修改原图,必须通过原图创建一个同样大小的Bitmap,并将原图绘制到新的bitmap中。直接修改原图会报错java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor。
在这里插入图片描述

3.使用颜色矩阵来改变图片

  接下来我们通过直接修改矩阵中的值来改变图片的显示效果。
布局文件xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/mm_iv"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="2" /><GridLayoutandroid:id="@+id/mm_gl"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="3"android:columnCount="5"android:rowCount="4" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:layout_marginEnd="10dp"android:orientation="horizontal"><Buttonandroid:id="@+id/mm_but_change"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="改变" /><Buttonandroid:id="@+id/mm_but_reset"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="20dp"android:layout_weight="1"android:text="重置" /></LinearLayout></LinearLayout>

  动态创建edittext,添加到gridlayout

    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_mmactivity);mm_but_change = findViewById(R.id.mm_but_change);mm_but_reset = findViewById(R.id.mm_but_reset);mm_iv = findViewById(R.id.mm_iv);mm_gl = findViewById(R.id.mm_gl);bm = BitmapFactory.decodeResource(getResources(), R.mipmap.dgdfg);mm_iv.setImageBitmap(bm);mm_gl.post(new Runnable() {@Overridepublic void run() {etWidth = mm_gl.getWidth() / 5;etHeight = mm_gl.getHeight() / 4;addEts();initMatrix();}});}/*** 添加edittext*/private void addEts() {for (int i = 0; i < ets.length; i++) {EditText editText = new EditText(this);editText.setGravity(Gravity.CENTER);ets[i] = editText;mm_gl.addView(editText, etWidth, etHeight);}}/*** 设置edittext的值*/private void initMatrix() {for (int i = 0; i < ets.length; i++) {if (i % 6 == 0) {ets[i].setText(1 + "");} else {ets[i].setText(0 + "");}}}

  获得修改后的EditText值,将矩阵值设置给颜色矩阵。

    private void getMatrix() {for (int i = 0; i < 20; i++) {colorM[i] = Float.valueOf(ets[i].getText().toString());}}private void setImageMatrix() {Bitmap bitmap = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);ColorMatrix colorMatrix = new ColorMatrix();colorMatrix.set(colorM);Canvas canvas = new Canvas(bitmap);Paint paint = new Paint();paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));canvas.drawBitmap(bm, 0, 0, paint);mm_iv.setImageBitmap(bitmap);}

  最后,设置点击事件,重置是将图片还原,改变是将现有的矩阵作用到图片。

        mm_but_change.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {getMatrix();setImageMatrix();}});mm_but_reset.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {initMatrix();getMatrix();setImageMatrix();}});

在这里插入图片描述

3.1几种图片颜色矩阵处理效果

3.1.1 灰度效果

{ 0.33 0.59 0.11 0 0 0.33 0.59 0.11 0 0 0.33 0.59 0.11 0 0 0 0 0 1 0 } \left\{ \begin{matrix} 0.33 & 0.59 & 0.11 & 0 & 0\\ 0.33 & 0.59 & 0.11 & 0 & 0 \\ 0.33 &0.59 & 0.11& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} 0.330.330.3300.590.590.5900.110.110.11000010000
在这里插入图片描述

3.1.2 图像颜色反转

{ − 1 0 0 1 1 0 − 1 0 1 1 0 0 − 1 1 1 0 0 0 1 0 } \left\{ \begin{matrix} -1 & 0 & 0 & 1 & 1\\ 0 & -1 & 0 & 1 & 1 \\ 0 &0 & -1& 1& 1 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} 10000100001011111110
在这里插入图片描述

3.1.3 怀旧效果

{ 0.393 0.769 0.189 0 0 0.349 0.686 0.168 0 0 0.272 0.534 0.131 0 0 0 0 0 1 0 } \left\{ \begin{matrix} 0.393 & 0.769 & 0.189 & 0 &0\\ 0.349 &0.686 & 0.168 & 0 & 0\\ 0.272 &0.534 & 0.131& 0& 0 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} 0.3930.3490.27200.7690.6860.53400.1890.1680.131000010000
在这里插入图片描述

3.1.4 去色效果

{ 1.5 1.5 1.5 0 − 1 1.5 1.5 1.5 0 − 1 1.5 1.5 1.5 0 − 1 0 0 0 1 0 } \left\{ \begin{matrix} 1.5 & 1.5 & 1.5 & 0 &-1\\ 1.5 &1.5 & 1.5 & 0 & -1\\ 1.5 &1.5 & 1.5& 0& -1 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} 1.51.51.501.51.51.501.51.51.5000011110
在这里插入图片描述

3.1.5 高饱和度

{ 1.438 − 0.112 − 0.016 0 − 0.03 − 0.062 1.378 − 0.016 0 0.05 − 0.062 − 0.122 1.483 0 − 0.02 0 0 0 1 0 } \left\{ \begin{matrix} 1.438 & -0.112 & -0.016 & 0 &-0.03\\ -0.062 &1.378 & -0.016 & 0 & 0.05\\ -0.062 &-0.122 & 1.483& 0& -0.02 \\ 0 & 0 & 0 & 1 & 0 \end{matrix} \right\} 1.4380.0620.06200.1121.3780.12200.0160.0161.483000010.030.050.020
在这里插入图片描述

4.像素点分析

  通过改变每个像素点argb值,来达到修改图片。android系统提供了Bitmap.getPixels()方法来获取这个bitmap的像素点。

bm.getPixels(int[] pixels, int offset, int stride,int x, int y, int width, int height)
pixels:接收每个点的颜色
offset:写入到pixels中的第一个像素索引值
stride:pixels中的行间距
x:从位图中读取的第一个像素的X坐标值
y:从位图中读取的第一个像素的y坐标值
width:从每一行中读取的像素宽度
height:读取的行数

一般使用

bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);

具体代码

 public Bitmap handleImagePixelsOldPhoto(Bitmap bm) {//由于不能修改原始图片,需要创建一个图片的副本bmp Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),Bitmap.Config.ARGB_8888);int width = bm.getWidth();int height = bm.getHeight();int color = 0;int r, g, b, a, r1, g1, b1;//初始化像素数组的大小int[] oldPx = new int[width * height];int[] newPx = new int[width * height];//获取像素点bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);for (int i = 0; i < width * height; i++) {color = oldPx[i];a = Color.alpha(color);r = Color.red(color);g = Color.green(color);b = Color.blue(color);//效果的公式,用来改变像素点的颜色r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);//最大值255if (r1 > 255) {r1 = 255;}if (g1 > 255) {g1 = 255;}if (b1 > 255) {b1 = 255;}newPx[i] = Color.argb(a, r1, g1, b1);}bmp.setPixels(newPx, 0, width, 0, 0, width, height);return bmp;}

在这里插入图片描述

4.1常用图像像素点处理效果

4.1.1 底片效果

处理方法都是前辈们研究出来的,这里我们只是使用。贴出代码和效果图。

    public static Bitmap handleImageNegative(Bitmap bm) {int width = bm.getWidth();int height = bm.getHeight();int color;int r, g, b, a;Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);int[] oldPx = new int[width * height];int[] newPx = new int[width * height];bm.getPixels(oldPx, 0, width, 0, 0, width, height);for (int i = 0; i < width * height; i++) {color = oldPx[i];r = Color.red(color);g = Color.green(color);b = Color.blue(color);a = Color.alpha(color);r = 255 - r;g = 255 - g;b = 255 - b;if (r > 255) {r = 255;} else if (r < 0) {r = 0;}if (g > 255) {g = 255;} else if (g < 0) {g = 0;}if (b > 255) {b = 255;} else if (b < 0) {b = 0;}newPx[i] = Color.argb(a, r, g, b);}bmp.setPixels(newPx, 0, width, 0, 0, width, height);return bmp;}

在这里插入图片描述

4.1.2 浮雕效果

直接贴代码。

 public static Bitmap handleImagePixelsRelief(Bitmap bm) {Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),Bitmap.Config.ARGB_8888);int width = bm.getWidth();int height = bm.getHeight();int color = 0, colorBefore = 0;int a, r, g, b;int r1, g1, b1;int[] oldPx = new int[width * height];int[] newPx = new int[width * height];bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);for (int i = 1; i < width * height; i++) {colorBefore = oldPx[i - 1];a = Color.alpha(colorBefore);r = Color.red(colorBefore);g = Color.green(colorBefore);b = Color.blue(colorBefore);color = oldPx[i];r1 = Color.red(color);g1 = Color.green(color);b1 = Color.blue(color);r = (r - r1 + 127);g = (g - g1 + 127);b = (b - b1 + 127);if (r > 255) {r = 255;}if (g > 255) {g = 255;}if (b > 255) {b = 255;}newPx[i] = Color.argb(a, r, g, b);}bmp.setPixels(newPx, 0, width, 0, 0, width, height);return bmp;}

在这里插入图片描述

这篇关于Android学习笔记之ColorMatrix、图像处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056128

相关文章

Android中Dialog的使用详解

《Android中Dialog的使用详解》Dialog(对话框)是Android中常用的UI组件,用于临时显示重要信息或获取用户输入,本文给大家介绍Android中Dialog的使用,感兴趣的朋友一起... 目录android中Dialog的使用详解1. 基本Dialog类型1.1 AlertDialog(

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D

Android如何获取当前CPU频率和占用率

《Android如何获取当前CPU频率和占用率》最近在优化App的性能,需要获取当前CPU视频频率和占用率,所以本文小编就来和大家总结一下如何在Android中获取当前CPU频率和占用率吧... 最近在优化 App 的性能,需要获取当前 CPU视频频率和占用率,通过查询资料,大致思路如下:目前没有标准的

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后