您的位置:首页 > 健康 > 美食 > 安卓窗口window无法移除屏幕外超过屏幕边界?-wms源码层面深入剖析

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

2024/10/6 5:57:52 来源:https://blog.csdn.net/learnframework/article/details/141461055  浏览:    关键词:安卓窗口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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com