当前位置: 首页 > 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.lryc.cn/news/587505.html

相关文章:

  • Android编译系统——基础介绍(一)
  • LVS集群技术
  • 17.Python 中的相等性比较:== vs is
  • 云原生核心技术解析:Docker vs Kubernetes vs Docker Compose
  • 深入了解linux系统—— 进程信号的保存
  • 数据可视化全流程设计指南
  • Vue 低代码可视化表单设计器 FcDesigner v3.3 版本发布!表格布局升级+精细化权限控制
  • 前端常见十大问题讲解
  • Spark 之 like 表达式
  • SpringMVC4
  • UI前端与数字孪生结合实践探索:智慧物流的仓储自动化管理系统
  • pycharm恢复出厂设置,可以解决大多数pycharm存在的问题
  • 创建自定义Dataset类与多分类问题实战
  • 怎么解决数据库幻读问题
  • 【图片识别改名】水印相机拍的照片如何将照片的名字批量改为水印内容?图片识别改名的详细步骤和注意事项
  • 设计模式笔记_结构型_桥接模式
  • vscode 安装 esp ide环境
  • 基于MATLAB的LSTM长短期记忆神经网络的数据回归预测方法应用
  • 02 51单片机之LED闪烁
  • 前端同学,你能不能别再往后端传一个巨大的JSON了?
  • 构建完整工具链:GCC/G++ + Makefile + Git 自动化开发流程
  • 前端接入海康威视摄像头的三种方案
  • autoware激光雷达和相机标定
  • JAVA 设计模式 工厂
  • Docker搭建Redis分片集群
  • 鸿蒙应用开发: 鸿蒙项目中使用私有 npm 插件的完整流程
  • Kotlin集合接口
  • 常用的OTP语音芯片有哪些?
  • 前端性能与可靠性工程系列: 渲染、缓存与关键路径优化
  • Spring Boot - Spring Boot 集成 MyBatis 分页实现 PageHelper