razerdp / BasePopup

Android下打造通用便捷的PopupWindow弹窗库

Home Page:https://github.com/razerdp/BasePopup

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

android:fitsSystemWindows="true"没写的时候库内部运行了什么逻辑来适配导航栏,这个逻辑会出现bug吗?

SelectSex opened this issue · comments

  • 系统版本(必须)/ Redmi 6 Android8.0.1
  • 库版本(必须)/最新版

问题描述:
当配置了透明导航栏后:
<item name="android:windowTranslucentNavigation">true</item>
image

,app使用弹窗就是最简单的继承了Basepopwindow,在大部分手机上都可以让弹窗的底部在导航栏之上。
但是在Redmi 6 Android8.0.1上却导航栏覆盖了弹窗底部,刚好弹窗底部有个按钮需要点击,导致无法点击。
于是我加上了android:fitsSystemWindows="true",在Redmi 6 Android8.0.1上显示正常了,但是在其他手机上却
弹窗底部升高了两个 导航栏高度,
所以,这段逻辑里面,是弹窗内部的那个逻辑完成了自动适配导航栏,又为何在 Redmi 6 Android8.0.1上自动适配失效,这个是个值得讨论的问题
不设置透明导航栏
image

设置透明导航栏
image

手机参数
image

研究了一下午,有补了些沉浸式的知识,最后吧项目中的android:windowTranslucentNavigation">true去掉了,先解决问题再说

现有疑问如下,
我手上的其他手机,运行app后,因为设置了透明导航栏,所以加上了android:fitsSystemWindows="true",来让内容区下面抬升适应导航栏,顶部下移适应状态栏,然后启动了弹窗,弹窗检测到主题中的透明状态栏,所以,弹窗在Redmi 6 Android8.0.1上正确的将弹窗置于导航栏下方,但是其他的手机(我身边的其他手机)点击弹出弹窗后,没有根据activity的主题设置,正确的将弹窗置于导航栏上,而是根本没有检测到透明导航栏属性,默认就是弹窗在导航栏上方,直到今天发现Redmi 6 Android8.0.1准确的得到了透明导航栏指令,并将弹窗内容置于导航栏下,就发生了我今天提出的bug,两个手机,同样的设置却有了两种效果,我再两种效果间必须做出新的抉择,这里我也发现了android:fitsSystemWindows在正常activity和 popwindow的些许不同,比如activity默认都是全屏使用的我们通常会发现activity肯定是和状态栏有覆盖一说,所以加上android:fitsSystemWindows回自动设置状态栏适配,和导航栏适配,但是当我把android:fitsSystemWindows用在popwindow中后,不论弹窗内容区是否是全屏显示的,都会默认适配状态栏,比如我弹窗内容区只有屏幕3分之一,底部弹出,设置了透明导航栏后,我需要加上android:fitsSystemWindows来适配,回自动同时视频顶部,在内容区顶部产生和状态栏高度一样的padding,如果我内容区域有底色,就会看到仅仅只有3分之一屏幕弹窗却顶部和底部都有个适配区域,所以我只能放弃android:fitsSystemWindows适配,而是使用手动修改上下padding,

popup适配navigationbar是通过找decor下的id是否匹配navigationbackground的。

所以你可以layoutinspector查一下~

这个问题我下周再跟进,感谢提供这么详细的信息^o^

相关代码在PopupUiUtil下,方法名getNavigationBarBounds。

本周末我在外面,手机码字挺心塞的………

下周我会跟进的

根据上面评论的疑问,我调试代码跟踪Redmi 6 Android8.0.1在运行查找导航view的方法代码发现,设置透明导航栏以后,

  PopupUiUtils. getNavigationBarBounds方法的代码
    for (int i = 0, count = decorView.getChildCount(); i < count; i++) {
        final View child = decorView.getChildAt(i);
        final int id = child.getId();
        if (id != View.NO_ID) {
            String resourceEntryName = getResNameById(id);
            if ("navigationBarBackground".equals(resourceEntryName)
                    && child.getVisibility() == View.VISIBLE) {
                isVisible = true;
                break;
            }
        }
    }

及时Redmi 6 Android8.0.1手机状态栏是显示的,因为透明,所以以上for循环得到的导航栏view是空,调试完我就感觉拿到,当导航栏有颜色的时候,以上for循环才可以得到导航view,在非Redmi 6 Android8.0.1手机上即使设置了透明导航栏,上面for循环是可以得到导航栏view的。到这里问题基本上就清楚了,

Redmi 6 Android8.0.1手机有bug,当设置导航栏透明沉浸式后,导航栏显示,但是上面的for循环代码是找不到导航view的,

正在跟进,差不多就是如此,除了Redmi 6 Android8.0.1这个手机的自身bug导致获取导航栏view 的代码失效的问题外,就是
android:fitsSystemWindows在弹窗中的表现不尽人意,希望可以作者自己个PopupDecorViewProxy加入个调用就可以设置兼容上下导航栏和状态栏适配的方法,

还有弱弱的问下,弹窗中有recyclerview,recyclerview中有edittext,然后键盘的弹出的相关还能优化下不,
算了,键盘问题是个老大难,恶心的一批,最后我自定义数字键盘先用着了,键盘随着焦点丢失自动从数字键盘变成字母键盘,高度抖一抖,滑动列表回来获取焦点后,有从字母键盘变成数字键盘,还有就是键盘弹出延时300ms还能弹出,但是我想设置尽快弹出,就改为100ms,或者更短,就容易无法自动弹出键盘成功,键盘问题真是恼火,需要的知识点和兼容性知识也比较真是让人头大

大佬也别急,问题慢慢处理,手机码字辛苦了,哈哈

还有于是我看了看其他获取导航栏的方式里面遇到各种问题
比如布兰科鸡写的工具类中提到的三星手机导航栏自身问题

image

这种兼容问题最是头疼了

recycle键盘相关的文档有,可以去看看

研究了一下午,有补了些沉浸式的知识,最后吧项目中的android:windowTranslucentNavigation">true去掉了,先解决问题再说

现有疑问如下, 我手上的其他手机,运行app后,因为设置了透明导航栏,所以加上了android:fitsSystemWindows="true",来让内容区下面抬升适应导航栏,顶部下移适应状态栏,然后启动了弹窗,弹窗检测到主题中的透明状态栏,所以,弹窗在Redmi 6 Android8.0.1上正确的将弹窗置于导航栏下方,但是其他的手机(我身边的其他手机)点击弹出弹窗后,没有根据activity的主题设置,正确的将弹窗置于导航栏上,而是根本没有检测到透明导航栏属性,默认就是弹窗在导航栏上方,直到今天发现Redmi 6 Android8.0.1准确的得到了透明导航栏指令,并将弹窗内容置于导航栏下,就发生了我今天提出的bug,两个手机,同样的设置却有了两种效果,我再两种效果间必须做出新的抉择,这里我也发现了android:fitsSystemWindows在正常activity和 popwindow的些许不同,比如activity默认都是全屏使用的我们通常会发现activity肯定是和状态栏有覆盖一说,所以加上android:fitsSystemWindows回自动设置状态栏适配,和导航栏适配,但是当我把android:fitsSystemWindows用在popwindow中后,不论弹窗内容区是否是全屏显示的,都会默认适配状态栏,比如我弹窗内容区只有屏幕3分之一,底部弹出,设置了透明导航栏后,我需要加上android:fitsSystemWindows来适配,回自动同时视频顶部,在内容区顶部产生和状态栏高度一样的padding,如果我内容区域有底色,就会看到仅仅只有3分之一屏幕弹窗却顶部和底部都有个适配区域,所以我只能放弃android:fitsSystemWindows适配,而是使用手动修改上下padding,

注意:android:fitsSystemWindows 在大部分手机上都是半屏弹窗自动加顶部padding和底部padding,但是就是Redmi 6 Android8.0.1上设置弹窗根布局 android:fitsSystemWindows=true无效,应该和android:windowTranslucentNavigation">true,有关,
为啥在此续写注意事项:因为今天我继续想找个完美方案,最后找到了 ViewCompat.setOnApplyWindowInsetsListener方法上,然后今天用这个问题手机在弹窗根布局设置了android:fitsSystemWindows=true,突然发现不会自动加上下padding,我以为昨天发布的android:fitsSystemWindows自动加上下布局的问题反馈是我提错了,,折腾了好几十分钟都无法自动加上下padding,突然才恍然大悟,可能是这个手机的问题,换个正常手机就可以使用android:fitsSystemWindows=true了,
现在手上这个Redmi 6 Android8.0.1这种奇怪的bug我用另一个,Redmi 6 Android 9,也复现了,也是神奇,就这个机型有问题。。。,

可以运行下layoutinspector,把li文件导出来分享到git评论这里吗?

我快到家了,可以研究一下

可以

或者加下我微信razerdp

image
studio如何导出li文件,这个我还真没导出过,研究了一下还是没找到导出按钮

image
这是弹窗,加入了fitsSystemWindows

今天一直在研究可以,自己实现 fitsSystemWindows的测量导航栏高度的代码,找到了
ViewCompat.setOnApplyWindowInsetsListener
方法,但是这个知识基础太薄弱,英语也不太好,棘手呀,就希望大佬可以实现 测量 导航栏高度的代码,

我就可以在app】设置了透明导航栏的情况,给所有弹窗,设置
setOverlayNavigationBar(true)
setOverlayNavigationBarMode(BasePopupFlag.OVERLAY_CONTENT)
让弹窗也显示在导航栏下面,然后用 我们自己的 fitsSystemWindows的测量代码,手动padding,差不多就可以解决现在已有的问题了

注:手上的问题手机和正常手机在 弹窗主动设置了
setOverlayNavigationBar(true)
setOverlayNavigationBarMode(BasePopupFlag.OVERLAY_CONTENT)
后都是效果一致,弹窗在导航栏下方,在此一致的情况我才想着手动设置导航栏高度padding,苦于小白条,虚拟导航栏,等等高度都不一致。就发现 fitsSystemWindows 的测量导航栏高度的逻辑很强大,基本上手上的手机,activity设置了 fitsSystemWindows。都是准确测量导航栏高度了,

as 4.0之后导出li文件稍微有点小复杂~

shift 两次,然后键入 legacy layout inspector,捕捉后,在项目的captrues下有li文件

OnApplyWindowInsetsListener在解决navigationbar之前其实看到过了,但这货在api 21以上才有效,我们BasePopup最低支持16。。。被限制住了。。

razerdp.basepopup_2021.10.31_16.40-1.zip

我项目最低21,要不先把这个功能搞起来,19的手机我都不适配了。。。。

噗,我不可能为了你把通用库改掉的。。。。我的库使用者还存在4.x的人的说

另外你的li我需要decorview的,popup的可以不用。

li文件的信息也太少了,还只能截取一层窗口,截取的图上连导航栏都看不到,
image
activity的截取razerdp.basepopup_2021.10.31_16.44.zip

我说你可以加上功能,然后告知,仅支持21以上,哈哈,大部分都用户先满足了

噗,不可以随便加的~

得先找到原理嘛= =

不过确实navigationbar都没了,估计是这台红米的ROOM做过奇怪的处理,如果navigationbar都找不到,那么库会理所当然的认为没有导航栏了。。。

加我微信吧,我们微信聊

或者这个功能写成一个工具类,放在demo中,可以开发者自己调用,关键是这个东西我写的有点吃力,经验有不足,写不好。
微信等晚上吧,我手机今天没带到公司,走的急加班中

关键是,fitsSystemWindows在activity中表现正常,弹窗就无效了在这个红米6上,坑死了,我现在只能先写死加上padding了,我项目默认是透明导航栏的,加上总是对的

话说,为啥要在弹窗中加fitsystemwindow

微信截图_20211031210034

我的红米平板试了一下,android 10,没啥问题,。

估计是特定机型的问题了

话说,为啥要在弹窗中加fitsystemwindow

这个红米6上,弹窗底部在导航栏下显示,就是我上面给你截的图,我项目弹窗底部是有提交按钮的。导航栏盖住,我就没法点击按钮了,要么自己加padding要么使用fitsSystemWindows,但是fitsSystemWindows 竟然是无效的。。。。

emmm,我复现了,windowTranslucentNavigation的时候,navigationbar直接没了。

然而小米ROM给它加上了哈哈哈哈

而我用系统的原生模拟器,navigation没有去掉,只是没了background而已

ROM坑爹

微信截图_20211031210542

微信截图_20211031210715

可以,我去研究一下

可以,我去研究一下

哈哈哈,你复现了,看来解决问题的时候不远了,开心

可以,我去研究一下

注意这个bug手机的activiyt是可以正常使用fitsSystemWindows,得到这个假的导航栏的高度的,这就很屌了

@SelectSex

初步修复了一下,请更新到3.2.1-SNAPSHOT

当前修复方案简述如下:通过WindowInsets二次判断

详述如下:

ProxyView增加insets监听:

https://github.com/razerdp/BasePopup/blob/dev/lib/src/main/java/razerdp/basepopup/PopupDecorViewProxy.java#L89

PopupHelper增加二次Nav确认:

https://github.com/razerdp/BasePopup/blob/dev/lib/src/main/java/razerdp/basepopup/BasePopupHelper.java#L570

牛逼,一个方法就完成了,效果很好,就像默认就用上了fitsystemwindos一样,需要弹窗沉入导航栏只需要
setOverlayNavigationBar(true)
setOverlayNavigationBarMode(BasePopupFlag.OVERLAY_CONTENT)
即可,nice