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

安卓窗口window无法移除屏幕外超过屏幕边界?-wms源码层面深入剖析

背景

学习了上一节的窗口位置变化相关的内容后,在窗口移动过程过程中发现有一个限制问题,大家可以看一下如下动态图:
在这里插入图片描述

已经尽力把窗口想要拖到屏幕外面,但是一直拖到不生效,只能在屏幕内部进行移动,这个到其实很奇怪,因为对于LayoutParam的x,y坐标是有进行设置的,为啥设置了就不生效呢?

这里看看是不是应用层面还是哪里限制了,可以通过wms的Relayout的Attribute属性看看,明显看到有负数坐标,即app层面已经把移除屏幕的x坐标传递到了wms,但是最后wms并没有让这个传递来的坐标生效。
在这里插入图片描述

分析为啥不可以超出屏幕边界

这里要分析就一样也要日志中开始分析
frameworks/base/core/java/android/view/WindowLayout.java
在这里插入图片描述
前面分析位置变化就这里Gravity.apply坐标就有了变化,这里我们看看日志:
在这里插入图片描述
可以看到这里的Gravity.apply执行完成后确实x方向坐标是负的,但是继续往下看看computeFrames自带的日志:
在这里插入图片描述
却得到如下结果:
在这里插入图片描述
可以看到x的坐标其实从-93变成了0,这里最后的打印也就是实际显示的,那么到底是哪里吧-93变成0呢?

在这里插入图片描述
这里再查阅代码发现有个二fitToDisplay,即这里看着有个适配屏幕操作,也会改变这个坐标,这里也加入一下打印
在这里插入图片描述

从日志也可以看出来:
在这里插入图片描述

剖析一下fitToDisplay

  final boolean fitToDisplay = !inMultiWindowMode|| ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);

注意可以看到这里有多个限制,如果想让fitToDisplay不为true,其实还是有较多方法,这里可以考虑noLimits

        final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;

再看看applyDisplay方法

    public static void applyDisplay(int gravity, @NonNull Rect display, @NonNull Rect inoutObj) {if ((gravity&DISPLAY_CLIP_VERTICAL) != 0) {if (inoutObj.top < display.top) inoutObj.top = display.top;if (inoutObj.bottom > display.bottom) inoutObj.bottom = display.bottom;} else {int off = 0;if (inoutObj.top < display.top) off = display.top-inoutObj.top;else if (inoutObj.bottom > display.bottom) off = display.bottom-inoutObj.bottom;if (off != 0) {if (inoutObj.height() > (display.bottom-display.top)) {inoutObj.top = display.top;inoutObj.bottom = display.bottom;} else {inoutObj.top += off;inoutObj.bottom += off;}}}if ((gravity&DISPLAY_CLIP_HORIZONTAL) != 0) {if (inoutObj.left < display.left) inoutObj.left = display.left;if (inoutObj.right > display.right) inoutObj.right = display.right;} else {int off = 0;if (inoutObj.left < display.left) off = display.left-inoutObj.left;else if (inoutObj.right > display.right) off = display.right-inoutObj.right;if (off != 0) {if (inoutObj.width() > (display.right-display.left)) {inoutObj.left = display.left;inoutObj.right = display.right;} else {inoutObj.left += off;inoutObj.right += off;}}}}

明显可以看出这里会对设置的frame的left和display的left,这样就把我们最后窗口显示限制在display以内。

那么问题就清楚了,其实本质就是因为computeFrames的里面有个applyDisplay方法会判断是否超出屏幕,从而让window限制显示在屏幕里面。

解决超出屏幕限制方法:

上面分析fitToDisplay有提到这个标志就是限制根本

final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;final boolean fitToDisplay = !inMultiWindowMode|| ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);

但是这个标志实际上app层面是可以控制的,考虑把这里的noLimits对应的FLAG_LAYOUT_NO_LIMITS带上,尝试看看
在这里插入图片描述
再运行测试如下:
在这里插入图片描述

完美运行,可以正常超出屏幕边界。

投屏专题部分:
https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg

更多framework详细代码和资料参考如下链接

hal+perfetto+surfaceflinger

https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
在这里插入图片描述

其他课程七件套专题:在这里插入图片描述
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频试看:
https://www.bilibili.com/video/BV1wc41117L4/

参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615

更多framework假威风耗:androidframework007


http://www.mrgr.cn/news/5554.html

相关文章:

  • 【JVM】剖析字符串与数组的底层实现(二)
  • 微服务CI/CD实践(一)环境准备及虚拟机创建
  • 深入剖析Self-Attention自注意力机制【图解】
  • Stable Diffusion AI绘画工具的安装与配置(MAC用户)
  • 日志审计Graylog 使用教程-kafka收取消息
  • [数据集][目标检测]航拍屋顶检测数据集VOC+YOLO格式458张3类别
  • 硬件与上位机之间常用的协议帧
  • Web Edge浏览器访问http时转成了https
  • spark全面个人总结(20个面试点)非网文 持续更新中
  • Java集合框架-Queue
  • jQuery的CSS操作
  • Google搜索语法
  • 学习记录——day32 子网掩码 域名解析
  • OpenCV几何图像变换(7)重映射函数 remap()的使用
  • Redis非关系型数据库
  • 主机ssh连接不上vmware的虚拟机
  • 水凝胶结机器人咋自主运动?利用拓扑调用的自我调节!
  • AWS 注册一年后是否需要花钱?
  • UDS 诊断 - ReadDataByPeriodicIdentifier(按周期性标识符读取数据)(0x2A)服务
  • wincc报警如何通过短信发送给手机