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

Android 16系统源码_窗口动画(一)窗口过渡动画层级图分析

一 窗口过渡动画

1.1 案例效果图

效果图

1.2 案例源码

1.2.1 添加权限 (AndroidManifest.xml)

<!-- 系统悬浮窗权限(Android 6.0+需动态请求) -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

1.2.2 窗口显示动画 (win_anim_enter.xml)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><scaleandroid:duration="1000"android:fromXScale="0.2"android:fromYScale="0.2"android:toXScale="1"android:toYScale="1" /><alphaandroid:duration="1000"android:fromAlpha="0.2"android:toAlpha="1" />
</set>

1.2.3 窗口移除动画 (win_anim_exit.xml)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><scaleandroid:duration="1000"android:fromXScale="0.2"android:fromYScale="0.2"android:toXScale="1"android:toYScale="1" /><alphaandroid:duration="1000"android:fromAlpha="0.2"android:toAlpha="1" />
</set>

1.2.4 动画样式 (themes.xml)

<?xml version="1.0" encoding="utf-8"?>
<resources><style name="floatAnimStyle"><item name="android:windowEnterAnimation">@anim/win_anim_enter</item><item name="android:windowExitAnimation">@anim/win_anim_exit</item></style>
</resources>

1.2.5 布局文件 (activity_main.xml)

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"><Buttonandroid:id="@+id/btnAdd"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="添加窗口"/><Buttonandroid:id="@+id/btnRemove"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="移除窗口"/>
</LinearLayout>

1.2.6 悬浮窗布局 (float_layout.xml)

<TextView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/floatingView"android:layout_width="200dp"android:layout_height="100dp"android:background="#77000000"android:text="悬浮窗口"android:textColor="#FF0000"android:gravity="center"/>

1.2.7 MainActivity 实现

public class MainActivity extends AppCompatActivity {private static final int REQUEST_OVERLAY_PERMISSION = 100;private WindowManager mWindowManager;private View mFloatView;private WindowManager.LayoutParams layoutParams;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 初始化mWindowManagermWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);findViewById(R.id.btnAdd).setOnClickListener(v -> addFloatingWindow());findViewById(R.id.btnRemove).setOnClickListener(v -> removeFloatingWindow());}private void addFloatingWindow() {// 检查悬浮窗权限if (!Settings.canDrawOverlays(this)) {requestOverlayPermission();return;}if (mFloatView != null) return;  // 防止重复添加// 创建悬浮窗视图mFloatView = LayoutInflater.from(this).inflate(R.layout.float_layout, null);mFloatView.setOnTouchListener(new ViewTouchListener());// 设置窗口参数int type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, type, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);// 初始位置layoutParams.gravity = Gravity.TOP | Gravity.START;layoutParams.x = 100;layoutParams.y = 300;layoutParams.windowAnimations = R.style.floatAnimStyle; //窗口过渡动画try {mWindowManager.addView(mFloatView, layoutParams);} catch (Exception e) {Toast.makeText(this, "添加失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();}}private void removeFloatingWindow() {if (mFloatView != null) {try {mWindowManager.removeView(mFloatView);mFloatView = null;} catch (Exception e) {Toast.makeText(this, "移除失败", Toast.LENGTH_SHORT).show();}}}// 处理拖拽的触摸监听器private class ViewTouchListener implements View.OnTouchListener {private int initialX, initialY;private float initialTouchX, initialTouchY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:initialX = layoutParams.x;initialY = layoutParams.y;initialTouchX = event.getRawX();initialTouchY = event.getRawY();return true;case MotionEvent.ACTION_MOVE:layoutParams.x = initialX + (int) (event.getRawX() - initialTouchX);layoutParams.y = initialY + (int) (event.getRawY() - initialTouchY);mWindowManager.updateViewLayout(mFloatView, layoutParams);return true;}return false;}}// 请求悬浮窗权限private void requestOverlayPermission() {Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_OVERLAY_PERMISSION) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {addFloatingWindow();}}}@Overrideprotected void onDestroy() {removeFloatingWindow(); // 防止Activity销毁后窗口残留super.onDestroy();}
}

二 过渡动画层级图分析

2.1 使用winscope抓取SurfaceFlinger图层信息

抓取图层信息。

adb shell su root service call SurfaceFlinger 1025 i32 1 #开始录制
adb shell su root service call SurfaceFlinger 1025 i32 0 #停止录制
adb pull /data/misc/wmtrace . //获取捕获的SurfaceFlinger图层信

使用adb指令将抓取的SurfaceFlinger图层信息导出来。
SurfaceFlinger图层信息

2.2 使用winscope进行分析

2.2.1 窗口未被添加到WMS中

01
层级树的叶子节点Leaf:3:14#0还看不到我们的窗口节点。

2.2.2 窗口被添加到WMS中

02
可以在层级树的叶子节点Leaf:3:14#0看到新加的Sys2038窗口图层信息。

2.2.3 窗口显示过渡动画开始

03

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><scaleandroid:duration="1000"android:fromXScale="0.2"android:fromYScale="0.2"android:toXScale="1"android:toYScale="1" /><alphaandroid:duration="1000"android:fromAlpha="0.2"android:toAlpha="1" />
</set>

多了一个含有animation-leash关键字的Surface图层,bounds接近我们在动画样式文件win_anim_enter.xml里面设置的初始值0.2倍,透明度同样接近我们设置的初始值0.2。

2.2.4 窗口显示过渡动画即将结束

04
bound接近1.0,透明度也接近1.0,过渡动画即将执行完毕。

2.2.5 窗口显示过渡动画结束

05
animation-leash关键字的Surface图层被移除,只剩下我们要添加的类型为Sys2038的窗口图层。

2.2.6 窗口准备被移除,开始执行过渡动画

06

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><scaleandroid:duration="1000"android:fromXScale="1"android:fromYScale="1"android:toXScale="0.2"android:toYScale="0.2" /><alphaandroid:duration="1000"android:fromAlpha="1"android:toAlpha="0.2" /></set>

多了一个含有animation-leash关键字的Surface图层,bounds是我们在动画样式文件win_anim_exit.xml里面设置的初始值1.0倍,透明度同样是我们设置的初始值1.0。

2.2.7 窗口被移除过渡动画即将结束

07
bound接近0.2,透明度也接近0.2,过渡动画即将执行完毕。

2.2.8 窗口被移除过渡动画结束

08
animation-leash关键字的Surface图层被移除,类型为Sys2038的之前添加的窗口图层也被移除,层级树的叶子节点Leaf:3:14#0恢复到了原来的样式。

2.3 窗口过渡动画期间的图层信息变化

过渡动画

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

相关文章:

  • USB读写自动化压力测试
  • Android编译系统——基础介绍(一)
  • 微软发布BioEmu模型
  • spring shell 基础使用
  • PyTorch生成式人工智能(17)——变分自编码器详解与实现
  • 大话数据结构之 <链表>(C语言)
  • 8.服务通信:Feign深度优化 - 解密声明式调用与现代负载均衡内核
  • UV vs Pip:Python 包管理的革命性进化
  • 017 进程控制 —— 终止进程
  • CentOS 7服务器上使用Docker部署Notesnook的详细指导说明
  • Python爬虫打怪升级:数据获取疑难全解析
  • 天地图前端实现geoJson与wkt格式互转
  • C++面试5题--4day
  • Java陷阱之assert关键字详解
  • 使用layui的前端框架过程中,无法加载css和js怎么办?
  • 谷歌开源库gtest 框架安装与使用
  • CentOS系统哪些版本?分别适用于那些业务或网站类型?
  • 2025年Java后端社招面试:高频场景题+八股文面试题解析
  • toString
  • S7-1200 中 AT 覆盖参数的应用:灵活访问数据区域的实用指南
  • 借助DeepSeek编写输出漂亮表格的chdb客户端
  • 电流驱动和电压驱动的区别
  • Rust语言实战:LeetCode算法精解
  • iOS高级开发工程师面试——RunLoop
  • FRP Ubuntu 服务端 + MacOS 客户端配置
  • 安装llama-factory报错 error: subprocess-exited-with-error
  • Kubernetes的微服务
  • c语言内存函数以及数据在内存中的存储
  • linux 文件搜索与文件内容查看
  • 嵌入式硬件篇---单稳态多谐施密特电路