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

相关文章:

  • 在 Azure Linux 上安装 RustFS
  • 如何保护文件传输安全?文件传输加密
  • 实战:如何创建 AWS RDS 数据库
  • 从“有”到“优”:iPaaS 赋能企业 API 服务治理建设
  • Foundry 私钥管理指南:方法与安全最佳实践
  • 上下文管理器 和 contextlib 模块
  • 深入浅出Kafka Producer源码解析:架构设计与编码艺术
  • VMware 虚拟机装 Linux Centos 7.9 保姆级教程(附资源包)
  • mybatis-plus-jpa-support
  • 常用的OTP语音芯片有哪些?
  • Spring Boot启动原理:从main方法到内嵌Tomcat的全过程
  • Linux 系统下的 Sangfor VDI 客户端安装与登录完全攻略 (CentOS、Ubuntu、麒麟全线通用)
  • Git LFS 操作处理Github上传大文件操作记录
  • 第一章编辑器开发基础第一节绘制编辑器元素_4输入字段(4/7)
  • Redis集群方案——Redis分片集群
  • 《星盘接口4:银河守护者》
  • 小波变换 | Haar 小波变换
  • 浏览器自动化领域的MCP
  • 实战--Tlias教学管理系统(部门管理)
  • 纯CSS轮播
  • SAP ERP与微软ERP dynamics对比,两款云ERP产品有什么区别?
  • 【第零章编辑器开发与拓展】
  • 不用下载软件也能录屏?Windows 10 自带录屏功能详解
  • Postman、Apifox、Apipost用哪个? 每个的优缺点和综合比较(个人观点)
  • qt多线程的实战使用
  • 【记录】BLE|百度的旧蓝牙随身音箱手机能配对不能连接、电脑能连接不能使用的解决思路(Wireshark捕获并分析手机蓝牙报文)
  • Linux(Ubuntu)硬盘使用情况解析(已房子举例)
  • HTML面试题
  • 消费 Kafka 一个TOPIC数据,插入到另一个KAFKA的TOPIC
  • python学习2